aiobungie

A Pythonic async/await wrapper for interacting with the Bungie API.

Base client.

Example
import aiobungie

client = aiobungie.Client('YOUR_API_KEY')

# Search for Destiny2 users.
async def main() -> None:
    users = await client.search_users('Crit')

    # Iterate over the users and take the first 5 results.
    for user in users.take(5):
        print(f'{user.name} ({user.code})')

        # Iterate through the users memberships.
        for membership in user.memberships:
            print(membership.type, membership.id)

client.run(main()) # or asyncio.run(main())

Single RESTClient instance.

The difference between base client and the REST clients:

  • No Hight-Level concepts.
  • All returned data are pure JSON objects from the API.
  • No object creation.
Example
import aiobungie

async def main() -> None:
    # Using `async with` context manager to close the session properly.
    async with aiobungie.RESTClient("TOKEN") as rest:
        payload = await rest.fetch_player('Fate怒', 4275)

        for membership in payload:
            print(membership['membershipId'], membership['iconPath'])

import asyncio
asyncio.run(main())

REST client pool.

A REST client pool allows you to acquire multiple RESTClient instances that shares the same connection.

Example
import aiobungie
import asyncio

pool = aiobungie.RESTPool("token")

async def func1() -> None:
    async with pool.acquire() as instance:
        tokens = await instance.fetch_oauth2_tokens('code')
        pool.metadata['tokens'] = tokens

# Other instance may access the tokens from pool since its shared.

async def func2() -> None:
    async with pool.acquire() as instance:
        tokens = pool.metadata['tokens']
        tokens = await instance.refresh_access_token(tokens.refresh_token)

async def main() -> None:
    await asyncio.gather(func1(), func2())

asyncio.run(main())

Should you use the base client or the REST client? This returns to you. For an example if you're building a website.

You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects. Which gives you the freedom to deserialize it and implement your own logic in the front-end.

Or of you're building a Discord bot for an example or something simple. The base client is the way to go.

  1# MIT License
  2#
  3# Copyright (c) 2020 - Present nxtlo
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a copy
  6# of this software and associated documentation files (the "Software"), to deal
  7# in the Software without restriction, including without limitation the rights
  8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9# copies of the Software, and to permit persons to whom the Software is
 10# furnished to do so, subject to the following conditions:
 11#
 12# The above copyright notice and this permission notice shall be included in all
 13# copies or substantial portions of the Software.
 14#
 15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 21# SOFTWARE.
 22
 23"""A Pythonic `async`/`await` wrapper for interacting with the Bungie API.
 24
 25Base client.
 26
 27Example
 28-------
 29```py
 30import aiobungie
 31
 32client = aiobungie.Client('YOUR_API_KEY')
 33
 34# Search for Destiny2 users.
 35async def main() -> None:
 36    users = await client.search_users('Crit')
 37
 38    # Iterate over the users and take the first 5 results.
 39    for user in users.take(5):
 40        print(f'{user.name} ({user.code})')
 41
 42        # Iterate through the users memberships.
 43        for membership in user.memberships:
 44            print(membership.type, membership.id)
 45
 46client.run(main()) # or asyncio.run(main())
 47```
 48
 49Single RESTClient instance.
 50
 51The difference between base client and the REST clients:
 52
 53* No Hight-Level concepts.
 54* All returned data are pure JSON objects from the API.
 55* No object creation.
 56
 57Example
 58-------
 59```py
 60import aiobungie
 61
 62async def main() -> None:
 63    # Using `async with` context manager to close the session properly.
 64    async with aiobungie.RESTClient("TOKEN") as rest:
 65        payload = await rest.fetch_player('Fate怒', 4275)
 66
 67        for membership in payload:
 68            print(membership['membershipId'], membership['iconPath'])
 69
 70import asyncio
 71asyncio.run(main())
 72```
 73
 74REST client pool.
 75
 76A REST client pool allows you to acquire multiple `RESTClient` instances that shares the same connection.
 77
 78Example
 79-------
 80```py
 81import aiobungie
 82import asyncio
 83
 84pool = aiobungie.RESTPool("token")
 85
 86async def func1() -> None:
 87    async with pool.acquire() as instance:
 88        tokens = await instance.fetch_oauth2_tokens('code')
 89        pool.metadata['tokens'] = tokens
 90
 91# Other instance may access the tokens from pool since its shared.
 92
 93async def func2() -> None:
 94    async with pool.acquire() as instance:
 95        tokens = pool.metadata['tokens']
 96        tokens = await instance.refresh_access_token(tokens.refresh_token)
 97
 98async def main() -> None:
 99    await asyncio.gather(func1(), func2())
100
101asyncio.run(main())
102```
103
104Should you use the base client or the REST client?
105This returns to you. For an example if you're building a website.
106
107You can use python as a REST API in the backend with the RESTClient since all returned object are JSON objects.
108Which gives you the freedom to deserialize it and implement your own logic in the front-end.
109
110Or of you're building a Discord bot for an example or something simple. The base client is the way to go.
111"""
112
113
114from __future__ import annotations
115
116from aiobungie import builders
117from aiobungie import crates
118from aiobungie import interfaces
119from aiobungie import traits
120from aiobungie import typedefs
121from aiobungie import url
122from aiobungie.client import Client
123from aiobungie.error import *
124from aiobungie.internal import iterators
125from aiobungie.internal.assets import Image
126from aiobungie.internal.enums import *
127from aiobungie.internal.factory import Factory
128from aiobungie.internal.iterators import *
129from aiobungie.rest import *
130from aiobungie.undefined import Undefined
131from aiobungie.undefined import UndefinedOr
132from aiobungie.undefined import UndefinedType
133
134from ._info import __about__
135from ._info import __author__
136from ._info import __docs__
137from ._info import __email__
138from ._info import __license__
139from ._info import __url__
140from ._info import __version__
141
142# Alias for crate for backwards compatibility.
143crate = crates
144
145# Activity enums
146from .crates.activity import Difficulty
147
148# Components enums
149from .crates.components import ComponentFields
150from .crates.components import ComponentPrivacy
151
152# Entity enums
153from .crates.entity import GatingScope
154from .crates.entity import ObjectiveUIStyle
155from .crates.entity import ValueUIStyle
156
157# Fireteam enums.
158from .crates.fireteams import FireteamActivity
159from .crates.fireteams import FireteamDate
160from .crates.fireteams import FireteamLanguage
161from .crates.fireteams import FireteamPlatform
162
163# Records enums
164from .crates.records import RecordState
165
166__all__ = [mod for mod in dir() if not mod.startswith("_")]  # type: ignore
@attrs.define(auto_exc=True)
class AiobungieError(builtins.RuntimeError):
60@attrs.define(auto_exc=True)
61class AiobungieError(RuntimeError):
62    """Base exception class that all other errors inherit from."""

Base exception class that all other errors inherit from.

AiobungieError()
2def __init__(self, ):
3    BaseException.__init__(self, )

Method generated by attrs for class AiobungieError.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class AmmoType(builtins.int, aiobungie.Enum):
646@typing.final
647class AmmoType(int, Enum):
648    """AN enum for Detyiny 2 ammo types."""
649
650    NONE = 0
651    PRIMARY = 1
652    SPECIAL = 2
653    HEAVY = 3

AN enum for Detyiny 2 ammo types.

NONE = <AmmoType.NONE: 0>
PRIMARY = <AmmoType.PRIMARY: 1>
SPECIAL = <AmmoType.SPECIAL: 2>
HEAVY = <AmmoType.HEAVY: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class BadRequest(aiobungie.HTTPError):
160@attrs.define(auto_exc=True)
161class BadRequest(HTTPError):
162    """Bad requests exceptions."""
163
164    url: typing.Optional[typedefs.StrOrURL]
165    """The URL/endpoint caused this error."""
166
167    body: typing.Any
168    """The response body."""
169
170    headers: multidict.CIMultiDictProxy[str]
171    """The response headers."""
172
173    http_status: http.HTTPStatus = attrs.field(default=http.HTTPStatus.BAD_REQUEST)

Bad requests exceptions.

BadRequest( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>)
2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default):
3    self.message = message
4    self.url = url
5    self.body = body
6    self.headers = headers
7    self.http_status = http_status
8    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status)

Method generated by attrs for class BadRequest.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

http_status: http.HTTPStatus

The response status.

Inherited Members
HTTPError
message
builtins.BaseException
with_traceback
args
def CharacterError(message: str, http_status: http.HTTPStatus) -> None:
76@helpers.deprecated("o.2.5", removed_in="0.2.6")
77@attrs.define(auto_exc=True)
78class CharacterError(HTTPError):
79    """Raised when a encountering making a character-based request.
80
81    .. warning::
82        This is deprecated since 0.2.5 and will be removed in 0.2.6.
83    """

Raised when a encountering making a character-based request.

This is deprecated since 0.2.5 and will be removed in 0.2.6.

@typing.final
class ClanMemberType(builtins.int, aiobungie.Enum):
701@typing.final
702class ClanMemberType(int, Enum):
703    """An enum for bungie clan member types."""
704
705    NONE = 0
706    BEGINNER = 1
707    MEMBER = 2
708    ADMIN = 3
709    ACTING_FOUNDER = 4
710    FOUNDER = 5

An enum for bungie clan member types.

NONE = <ClanMemberType.NONE: 0>
BEGINNER = <ClanMemberType.BEGINNER: 1>
MEMBER = <ClanMemberType.MEMBER: 2>
ADMIN = <ClanMemberType.ADMIN: 3>
ACTING_FOUNDER = <ClanMemberType.ACTING_FOUNDER: 4>
FOUNDER = <ClanMemberType.FOUNDER: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Class(builtins.int, aiobungie.Enum):
477@typing.final
478class Class(int, Enum):
479    """An Enum for Destiny character classes."""
480
481    TITAN = 0
482    HUNTER = 1
483    WARLOCK = 2
484    UNKNOWN = 3

An Enum for Destiny character classes.

TITAN = <Class.TITAN: 0>
HUNTER = <Class.HUNTER: 1>
WARLOCK = <Class.WARLOCK: 2>
UNKNOWN = <Class.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Client(aiobungie.traits.ClientApp):
  61class Client(traits.ClientApp):
  62    """Standard Bungie API client application.
  63
  64    This client deserialize the REST JSON responses using `aiobungie.internal.factory.Factory`
  65    and returns `aiobungie.crates` Python object implementations of the responses.
  66
  67    A `aiobungie.RESTClient` REST client can also be used alone for low-level concepts.
  68
  69    Parameters
  70    -----------
  71    token: `str`
  72        Your Bungie's API key or Token from the developer's portal.
  73
  74    Other Parameters
  75    ----------------
  76    rest_client: `aiobungie.interfaces.RESTInterface | None`
  77        An optional rest client instance you can pass.
  78        If set to `None` then the client will use the default instance.
  79
  80    Example
  81    -------
  82    ```py
  83    TOKEN = "SOME_TOKEN"
  84    async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
  85        client = aiobungie.Client(TOKEN, rest_client=rest_client)
  86    ```
  87
  88    max_retries : `int`
  89        The max retries number to retry if the request hit a `5xx` status code.
  90    max_ratelimit_retries : `int`
  91        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
  92    client_secret : `str | None`
  93        An optional application client secret,
  94        This is only needed if you're fetching OAuth2 tokens with this client.
  95    client_id : `int | None`
  96        An optional application client id,
  97        This is only needed if you're fetching OAuth2 tokens with this client.
  98    """
  99
 100    __slots__ = ("_rest", "_factory", "_client_secret", "_client_id")
 101
 102    def __init__(
 103        self,
 104        token: str,
 105        /,
 106        client_secret: typing.Optional[str] = None,
 107        client_id: typing.Optional[int] = None,
 108        *,
 109        rest_client: typing.Optional[interfaces.RESTInterface] = None,
 110        max_retries: int = 4,
 111        max_ratelimit_retries: int = 3,
 112    ) -> None:
 113
 114        self._client_secret = client_secret
 115        self._client_id = client_id
 116
 117        self._rest = (
 118            rest_client
 119            if rest_client is not None
 120            else rest_.RESTClient(
 121                token,
 122                client_secret,
 123                client_id,
 124                max_retries=max_retries,
 125                max_ratelimit_retries=max_ratelimit_retries,
 126            )
 127        )
 128
 129        self._factory = factory_.Factory(self)
 130
 131    @property
 132    def factory(self) -> factory_.Factory:
 133        return self._factory
 134
 135    @property
 136    def rest(self) -> interfaces.RESTInterface:
 137        return self._rest
 138
 139    @property
 140    def request(self) -> Client:
 141        return copy.copy(self)
 142
 143    @property
 144    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 145        return self._rest.metadata
 146
 147    def run(
 148        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
 149    ) -> None:
 150        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
 151        try:
 152            if not loop.is_running():
 153                loop.set_debug(debug)
 154                loop.run_until_complete(future)
 155
 156        except Exception as exc:
 157            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
 158
 159        except KeyboardInterrupt:
 160            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
 161            return
 162
 163        finally:
 164            if self._rest.is_alive:
 165                # Clean up sessions.
 166                loop.run_until_complete(self._rest.close())
 167
 168    # * User methods.
 169
 170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
 171        """Fetch and return a user object of the bungie net user associated with account.
 172
 173        .. warning::
 174            This method requires OAuth2 scope and a Bearer access token.
 175
 176        Parameters
 177        ----------
 178        access_token : `str`
 179            A valid Bearer access token for the authorization.
 180
 181        Returns
 182        -------
 183        `aiobungie.crates.user.User`
 184            A user object includes the Destiny memberships and Bungie.net user.
 185        """
 186        resp = await self.rest.fetch_current_user_memberships(access_token)
 187
 188        return self.factory.deserialize_user(resp)
 189
 190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
 191        """Fetch a Bungie user by their BungieNet id.
 192
 193        .. note::
 194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
 195            for other memberships.
 196
 197        Parameters
 198        ----------
 199        id: `int`
 200            The user id.
 201
 202        Returns
 203        -------
 204        `aiobungie.crates.user.BungieUser`
 205            A Bungie user.
 206
 207        Raises
 208        ------
 209        `aiobungie.error.NotFound`
 210            The user was not found.
 211        """
 212        payload = await self.rest.fetch_bungie_user(id)
 213
 214        return self.factory.deserialize_bungie_user(payload)
 215
 216    async def search_users(
 217        self, name: str, /
 218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
 219        """Search for players and return all players that matches the same name.
 220
 221        Parameters
 222        ----------
 223        name : `buildins.str`
 224            The user name.
 225
 226        Returns
 227        -------
 228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
 229            A sequence of destiny memberships.
 230        """
 231        payload = await self.rest.search_users(name)
 232
 233        return iterators.FlatIterator(
 234            [
 235                self.factory.deserialize_searched_user(user)
 236                for user in payload["searchResults"]
 237            ]
 238        )
 239
 240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
 241        """Fetch all available user themes.
 242
 243        Returns
 244        -------
 245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
 246            A sequence of user themes.
 247        """
 248        data = await self.rest.fetch_user_themes()
 249
 250        return self.factory.deserialize_user_themes(data)
 251
 252    async def fetch_hard_types(
 253        self,
 254        credential: int,
 255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
 256        /,
 257    ) -> user.HardLinkedMembership:
 258        """Gets any hard linked membership given a credential.
 259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
 260        Cross Save aware.
 261
 262        Parameters
 263        ----------
 264        credential: `int`
 265            A valid SteamID64
 266        type: `aiobungie.CredentialType`
 267            The credential type. This must not be changed
 268            Since its only credential that works "currently"
 269
 270        Returns
 271        -------
 272        `aiobungie.crates.user.HardLinkedMembership`
 273            Information about the hard linked data.
 274        """
 275
 276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
 277
 278        return user.HardLinkedMembership(
 279            id=int(payload["membershipId"]),
 280            type=enums.MembershipType(payload["membershipType"]),
 281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
 282        )
 283
 284    async def fetch_membership_from_id(
 285        self,
 286        id: int,
 287        /,
 288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 289    ) -> user.User:
 290        """Fetch Bungie user's memberships from their id.
 291
 292        Notes
 293        -----
 294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
 295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
 296        see `aiobungie.crates.user.DestinyMembership` for more details.
 297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
 298
 299        Parameters
 300        ----------
 301        id : `int`
 302            The user's id.
 303        type : `aiobungie.MembershipType`
 304            The user's membership type.
 305
 306        Returns
 307        -------
 308        `aiobungie.crates.User`
 309            A Bungie user with their membership types.
 310
 311        Raises
 312        ------
 313        aiobungie.NotFound
 314            The requested user was not found.
 315        """
 316        payload = await self.rest.fetch_membership_from_id(id, type)
 317
 318        return self.factory.deserialize_user(payload)
 319
 320    async def fetch_user_credentials(
 321        self, access_token: str, membership_id: int, /
 322    ) -> collections.Sequence[user.UserCredentials]:
 323        """Fetch an array of credential types attached to the requested account.
 324
 325        .. note::
 326            This method require OAuth2 Bearer access token.
 327
 328        Parameters
 329        ----------
 330        access_token : `str`
 331            The bearer access token associated with the bungie account.
 332        membership_id : `int`
 333            The id of the membership to return.
 334
 335        Returns
 336        -------
 337        `collections.Sequence[aiobungie.crates.UserCredentials]`
 338            A sequence of the attached user credentials.
 339
 340        Raises
 341        ------
 342        `aiobungie.Unauthorized`
 343            The access token was wrong or no access token passed.
 344        """
 345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
 346
 347        return self.factory.deserialize_user_credentials(resp)
 348
 349    # * Destiny 2.
 350
 351    async def fetch_profile(
 352        self,
 353        member_id: int,
 354        type: typedefs.IntAnd[enums.MembershipType],
 355        components: list[enums.ComponentType],
 356        auth: typing.Optional[str] = None,
 357    ) -> components.Component:
 358        """
 359        Fetch a bungie profile passing components to the request.
 360
 361        Parameters
 362        ----------
 363        member_id: `int`
 364            The member's id.
 365        type: `aiobungie.MembershipType`
 366            A valid membership type.
 367        components : `list[aiobungie.ComponentType]`
 368            List of profile components to collect and return.
 369
 370        Other Parameters
 371        ----------------
 372        auth : `typing.Optional[str]`
 373            A Bearer access_token to make the request with.
 374            This is optional and limited to components that only requires an Authorization token.
 375
 376        Returns
 377        --------
 378        `aiobungie.crates.Component`
 379            A Destiny 2 player profile with its components.
 380            Only passed components will be available if they exists. Otherwise they will be `None`
 381
 382        Raises
 383        ------
 384        `aiobungie.MembershipTypeError`
 385            The provided membership type was invalid.
 386        """
 387        data = await self.rest.fetch_profile(member_id, type, components, auth)
 388        return self.factory.deserialize_components(data)
 389
 390    async def fetch_linked_profiles(
 391        self,
 392        member_id: int,
 393        member_type: typedefs.IntAnd[enums.MembershipType],
 394        /,
 395        *,
 396        all: bool = False,
 397    ) -> profile.LinkedProfile:
 398        """Returns a summary information about all profiles linked to the requested member.
 399
 400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
 401
 402        .. note::
 403            It will only return linked accounts whose linkages you are allowed to view.
 404
 405        Parameters
 406        ----------
 407        member_id : `int`
 408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
 409        member_type : `aiobungie.MembershipType`
 410            The type for the membership whose linked Destiny account you want to return.
 411
 412        Other Parameters
 413        ----------------
 414        all : `bool`
 415            If provided and set to `True`, All memberships regardless
 416            of whether they're obscured by overrides will be returned,
 417
 418            If provided and set to `False`, Only available memberships will be returned.
 419            The default for this is `False`.
 420
 421        Returns
 422        -------
 423        `aiobungie.crates.profile.LinkedProfile`
 424            A linked profile object.
 425        """
 426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
 427
 428        return self.factory.deserialize_linked_profiles(resp)
 429
 430    async def fetch_player(
 431        self,
 432        name: str,
 433        code: int,
 434        /,
 435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 436    ) -> collections.Sequence[user.DestinyMembership]:
 437        """Fetch a Destiny 2 player's memberships.
 438
 439        Parameters
 440        -----------
 441        name: `str`
 442            The unique Bungie player name.
 443        code : `int`
 444            The unique Bungie display name code.
 445        type: `aiobungie.internal.enums.MembershipType`
 446            The player's membership type, e,g. XBOX, STEAM, PSN
 447
 448        Returns
 449        --------
 450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
 451            A sequence of the found Destiny 2 player memberships.
 452            An empty sequence will be returned if no one found.
 453
 454        Raises
 455        ------
 456        `aiobungie.MembershipTypeError`
 457            The provided membership type was invalid.
 458        """
 459        resp = await self.rest.fetch_player(name, code, type)
 460
 461        return self.factory.deserialize_destiny_memberships(resp)
 462
 463    async def fetch_character(
 464        self,
 465        member_id: int,
 466        membership_type: typedefs.IntAnd[enums.MembershipType],
 467        character_id: int,
 468        components: list[enums.ComponentType],
 469        auth: typing.Optional[str] = None,
 470    ) -> components.CharacterComponent:
 471        """Fetch a Destiny 2 character.
 472
 473        Parameters
 474        ----------
 475        member_id: `int`
 476            A valid bungie member id.
 477        character_id: `int`
 478            The Destiny character id to retrieve.
 479        membership_type: `aiobungie.internal.enums.MembershipType`
 480            The member's membership type.
 481        components: `list[aiobungie.ComponentType]`
 482            Multiple arguments of character components to collect and return.
 483
 484        Other Parameters
 485        ----------------
 486        auth : `typing.Optional[str]`
 487            A Bearer access_token to make the request with.
 488            This is optional and limited to components that only requires an Authorization token.
 489
 490        Returns
 491        -------
 492        `aiobungie.crates.CharacterComponent`
 493            A Bungie character component.
 494
 495        `aiobungie.MembershipTypeError`
 496            The provided membership type was invalid.
 497        """
 498        resp = await self.rest.fetch_character(
 499            member_id, membership_type, character_id, components, auth
 500        )
 501
 502        return self.factory.deserialize_character_component(resp)
 503
 504    async def fetch_unique_weapon_history(
 505        self,
 506        membership_id: int,
 507        character_id: int,
 508        membership_type: typedefs.IntAnd[enums.MembershipType],
 509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
 510        """Fetch details about unique weapon usage for a character. Includes all exotics.
 511
 512        Parameters
 513        ----------
 514        membership_id : `int`
 515            The Destiny user membership id.
 516        character_id : `int`
 517            The character id to retrieve.
 518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 519            The Destiny user's membership type.
 520
 521        Returns
 522        -------
 523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
 524            A sequence of the weapon's extended values.
 525        """
 526        resp = await self._rest.fetch_unique_weapon_history(
 527            membership_id, character_id, membership_type
 528        )
 529
 530        return [
 531            self._factory.deserialize_extended_weapon_values(weapon)
 532            for weapon in resp["weapons"]
 533        ]
 534
 535    # * Destiny 2 Activities.
 536
 537    async def fetch_activities(
 538        self,
 539        member_id: int,
 540        character_id: int,
 541        mode: typedefs.IntAnd[enums.GameMode],
 542        *,
 543        membership_type: typedefs.IntAnd[
 544            enums.MembershipType
 545        ] = enums.MembershipType.ALL,
 546        page: int = 0,
 547        limit: int = 250,
 548    ) -> iterators.FlatIterator[activity.Activity]:
 549        """Fetch a Destiny 2 activity for the specified character id.
 550
 551        Parameters
 552        ----------
 553        member_id: `int`
 554            The user id that starts with `4611`.
 555        character_id: `int`
 556            The id of the character to retrieve the activities for.
 557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
 558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
 559
 560        Other Parameters
 561        ----------------
 562        membership_type: `aiobungie.internal.enums.MembershipType`
 563            The Member ship type, if nothing was passed than it will return all.
 564        page: int
 565            The page number. Default is `0`
 566        limit: int
 567            Limit the returned result. Default is `250`.
 568
 569        Returns
 570        -------
 571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
 572            An iterator of the player's activities.
 573
 574        Raises
 575        ------
 576        `aiobungie.MembershipTypeError`
 577            The provided membership type was invalid.
 578        """
 579        resp = await self.rest.fetch_activities(
 580            member_id,
 581            character_id,
 582            mode,
 583            membership_type=membership_type,
 584            page=page,
 585            limit=limit,
 586        )
 587
 588        return self.factory.deserialize_activities(resp)
 589
 590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
 591        """Fetch a post activity details.
 592
 593        Parameters
 594        ----------
 595        instance_id: `int`
 596            The activity instance id.
 597
 598        Returns
 599        -------
 600        `aiobungie.crates.PostActivity`
 601           A post activity object.
 602        """
 603        resp = await self.rest.fetch_post_activity(instance_id)
 604
 605        return self.factory.deserialize_post_activity(resp)
 606
 607    async def fetch_aggregated_activity_stats(
 608        self,
 609        character_id: int,
 610        membership_id: int,
 611        membership_type: typedefs.IntAnd[enums.MembershipType],
 612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
 613        """Fetch aggregated activity stats for a character.
 614
 615        Parameters
 616        ----------
 617        character_id: `int`
 618            The id of the character to retrieve the activities for.
 619        membership_id: `int`
 620            The id of the user that started with `4611`.
 621        membership_type: `aiobungie.internal.enums.MembershipType`
 622            The Member ship type.
 623
 624        Returns
 625        -------
 626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
 627            An iterator of the player's activities.
 628
 629        Raises
 630        ------
 631        `aiobungie.MembershipTypeError`
 632            The provided membership type was invalid.
 633        """
 634        resp = await self.rest.fetch_aggregated_activity_stats(
 635            character_id, membership_id, membership_type
 636        )
 637
 638        return self.factory.deserialize_aggregated_activities(resp)
 639
 640    # * Destiny 2 Clans or GroupsV2.
 641
 642    async def fetch_clan_from_id(
 643        self,
 644        id: int,
 645        /,
 646        access_token: typing.Optional[str] = None,
 647    ) -> clans.Clan:
 648        """Fetch a Bungie Clan by its id.
 649
 650        Parameters
 651        -----------
 652        id: `int`
 653            The clan id.
 654
 655        Returns
 656        --------
 657        `aiobungie.crates.Clan`
 658            An Bungie clan.
 659
 660        Raises
 661        ------
 662        `aiobungie.NotFound`
 663            The clan was not found.
 664        """
 665        resp = await self.rest.fetch_clan_from_id(id, access_token)
 666
 667        return self.factory.deserialize_clan(resp)
 668
 669    async def fetch_clan(
 670        self,
 671        name: str,
 672        /,
 673        access_token: typing.Optional[str] = None,
 674        *,
 675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 676    ) -> clans.Clan:
 677        """Fetch a Clan by its name.
 678        This method will return the first clan found with given name.
 679
 680        Parameters
 681        ----------
 682        name: `str`
 683            The clan name
 684
 685        Other Parameters
 686        ----------------
 687        access_token : `typing.Optional[str]`
 688            An optional access token to make the request with.
 689
 690            If the token was bound to a member of the clan,
 691            This field `aiobungie.crates.Clan.current_user_membership` will be available
 692            and will return the membership of the user who made this request.
 693        type : `aiobungie.GroupType`
 694            The group type, Default is aiobungie.GroupType.CLAN.
 695
 696        Returns
 697        -------
 698        `aiobungie.crates.Clan`
 699            A Bungie clan.
 700
 701        Raises
 702        ------
 703        `aiobungie.NotFound`
 704            The clan was not found.
 705        """
 706        resp = await self.rest.fetch_clan(name, access_token, type=type)
 707
 708        return self.factory.deserialize_clan(resp)
 709
 710    async def fetch_clan_conversations(
 711        self, clan_id: int, /
 712    ) -> collections.Sequence[clans.ClanConversation]:
 713        """Fetch the conversations/chat channels of the given clan id.
 714
 715        Parameters
 716        ----------
 717        clan_id : `int`
 718            The clan id.
 719
 720        Returns
 721        `collections.Sequence[aiobungie.crates.ClanConversation]`
 722            A sequence of the clan chat channels.
 723        """
 724        resp = await self.rest.fetch_clan_conversations(clan_id)
 725
 726        return self.factory.deserialize_clan_conversations(resp)
 727
 728    async def fetch_clan_admins(
 729        self, clan_id: int, /
 730    ) -> iterators.FlatIterator[clans.ClanMember]:
 731        """Fetch the clan founder and admins.
 732
 733        Parameters
 734        ----------
 735        clan_id : `int`
 736            The clan id.
 737
 738        Returns
 739        -------
 740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 741            An iterator over the found clan admins and founder.
 742
 743        Raises
 744        ------
 745        `aiobungie.NotFound`
 746            The requested clan was not found.
 747        """
 748        resp = await self.rest.fetch_clan_admins(clan_id)
 749
 750        return self.factory.deserialize_clan_members(resp)
 751
 752    async def fetch_groups_for_member(
 753        self,
 754        member_id: int,
 755        member_type: typedefs.IntAnd[enums.MembershipType],
 756        /,
 757        *,
 758        filter: int = 0,
 759        group_type: enums.GroupType = enums.GroupType.CLAN,
 760    ) -> collections.Sequence[clans.GroupMember]:
 761        """Fetch information about the groups that a given member has joined.
 762
 763        Parameters
 764        ----------
 765        member_id : `int`
 766            The member's id
 767        member_type : `aiobungie.MembershipType`
 768            The member's membership type.
 769
 770        Other Parameters
 771        ----------------
 772        filter : `int`
 773            Filter apply to list of joined groups. This Default to `0`
 774        group_type : `aiobungie.GroupType`
 775            The group's type.
 776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 777
 778        Returns
 779        -------
 780        `collections.Sequence[aiobungie.crates.GroupMember]`
 781            A sequence of joined groups for the fetched member.
 782        """
 783        resp = await self.rest.fetch_groups_for_member(
 784            member_id, member_type, filter=filter, group_type=group_type
 785        )
 786
 787        return [
 788            self.factory.deserialize_group_member(group) for group in resp["results"]
 789        ]
 790
 791    async def fetch_potential_groups_for_member(
 792        self,
 793        member_id: int,
 794        member_type: typedefs.IntAnd[enums.MembershipType],
 795        /,
 796        *,
 797        filter: int = 0,
 798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 799    ) -> collections.Sequence[clans.GroupMember]:
 800        """Fetch the potential groups for a clan member.
 801
 802        Parameters
 803        ----------
 804        member_id : `int`
 805            The member's id
 806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 807            The member's membership type.
 808
 809        Other Parameters
 810        ----------------
 811        filter : `int`
 812            Filter apply to list of joined groups. This Default to `0`
 813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
 814            The group's type.
 815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
 816
 817        Returns
 818        -------
 819        `collections.Sequence[aiobungie.crates.GroupMember]`
 820            A sequence of joined potential groups for the fetched member.
 821        """
 822        resp = await self.rest.fetch_potential_groups_for_member(
 823            member_id, member_type, filter=filter, group_type=group_type
 824        )
 825
 826        return [
 827            self.factory.deserialize_group_member(group) for group in resp["results"]
 828        ]
 829
 830    async def fetch_clan_members(
 831        self,
 832        clan_id: int,
 833        /,
 834        *,
 835        name: typing.Optional[str] = None,
 836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 837    ) -> iterators.FlatIterator[clans.ClanMember]:
 838        """Fetch Bungie clan members.
 839
 840        Parameters
 841        ----------
 842        clan_id : `int`
 843            The clans id
 844
 845        Other Parameters
 846        ----------------
 847        name : `typing.Optional[str]`
 848            If provided, Only players matching this name will be returned.
 849        type : `aiobungie.MembershipType`
 850            An optional clan member's membership type.
 851            This parameter is used to filter the returned results
 852            by the provided membership, For an example XBox memberships only,
 853            Otherwise will return all memberships.
 854
 855        Returns
 856        -------
 857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
 858            An iterator over the bungie clan members.
 859
 860        Raises
 861        ------
 862        `aiobungie.NotFound`
 863            The clan was not found.
 864        """
 865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
 866
 867        return self.factory.deserialize_clan_members(resp)
 868
 869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
 870        """Fetch the clan banners.
 871
 872        Returns
 873        -------
 874        `collections.Sequence[aiobungie.crates.ClanBanner]`
 875            A sequence of the clan banners.
 876        """
 877        resp = await self.rest.fetch_clan_banners()
 878
 879        return self.factory.deserialize_clan_banners(resp)
 880
 881    # This method is required to be here since it deserialize the clan.
 882    async def kick_clan_member(
 883        self,
 884        access_token: str,
 885        /,
 886        group_id: int,
 887        membership_id: int,
 888        membership_type: typedefs.IntAnd[enums.MembershipType],
 889    ) -> clans.Clan:
 890        """Kick a member from the clan.
 891
 892        .. note::
 893            This request requires OAuth2: oauth2: `AdminGroups` scope.
 894
 895        Parameters
 896        ----------
 897        access_token : `str`
 898            The bearer access token associated with the bungie account.
 899        group_id: `int`
 900            The group id.
 901        membership_id : `int`
 902            The member id to kick.
 903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
 904            The member's membership type.
 905
 906        Returns
 907        -------
 908        `aiobungie.crates.clan.Clan`
 909            The clan that the member was kicked from.
 910        """
 911        resp = await self.rest.kick_clan_member(
 912            access_token,
 913            group_id=group_id,
 914            membership_id=membership_id,
 915            membership_type=membership_type,
 916        )
 917
 918        return self.factory.deserialize_clan(resp)
 919
 920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
 921        """Fetch a Bungie clan's weekly reward state.
 922
 923        Parameters
 924        ----------
 925        clan_id : `int`
 926            The clan's id.
 927
 928        Returns
 929        -------
 930        `aiobungie.crates.Milestone`
 931            A runtime status of the clan's milestone data.
 932        """
 933
 934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
 935
 936        return self.factory.deserialize_milestone(resp)
 937
 938    # * Destiny 2 Entities aka Definitions.
 939
 940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
 941        """Fetch a static inventory item entity given a its hash.
 942
 943        Parameters
 944        ----------
 945        hash: `int`
 946            Inventory item's hash.
 947
 948        Returns
 949        -------
 950        `aiobungie.crates.InventoryEntity`
 951            A bungie inventory item.
 952        """
 953        resp = await self.rest.fetch_inventory_item(hash)
 954
 955        return self.factory.deserialize_inventory_entity(resp)
 956
 957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
 958        """Fetch a Destiny objective entity given a its hash.
 959
 960        Parameters
 961        ----------
 962        hash: `int`
 963            objective's hash.
 964
 965        Returns
 966        -------
 967        `aiobungie.crates.ObjectiveEntity`
 968            An objective entity item.
 969        """
 970        resp = await self.rest.fetch_objective_entity(hash)
 971
 972        return self.factory.deserialize_objective_entity(resp)
 973
 974    async def search_entities(
 975        self, name: str, entity_type: str, *, page: int = 0
 976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
 977        """Search for Destiny2 entities given a name and its type.
 978
 979        Parameters
 980        ----------
 981        name : `str`
 982            The name of the entity, i.e., Thunderlord, One thousand voices.
 983        entity_type : `str`
 984            The type of the entity, AKA Definition,
 985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
 986
 987        Other Parameters
 988        ----------------
 989        page : `int`
 990            An optional page to return. Default to 0.
 991
 992        Returns
 993        -------
 994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
 995            An iterator over the found results matching the provided name.
 996        """
 997        resp = await self.rest.search_entities(name, entity_type, page=page)
 998
 999        return self.factory.deserialize_inventory_results(resp)
1000
1001    # Fireteams
1002
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)
1055
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)
1119
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]
1147
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]
1203
1204    # Friends and social.
1205
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)
1228
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)
1251
1252    # Applications and Developer portal.
1253
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)
1270
1271    # Milestones
1272
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Standard Bungie API client application.

This client deserialize the REST JSON responses using aiobungie.Factory and returns aiobungie.crates Python object implementations of the responses.

A aiobungie.RESTClient REST client can also be used alone for low-level concepts.

Parameters
  • token (str): Your Bungie's API key or Token from the developer's portal.
Other Parameters
Example
TOKEN = "SOME_TOKEN"
async with aiobungie.RESTClient(TOKEN, max_retries=2) as rest_client:
    client = aiobungie.Client(TOKEN, rest_client=rest_client)

max_retries : int The max retries number to retry if the request hit a 5xx status code. max_ratelimit_retries : int The max retries number to retry if the request hit a 429 status code. Defaults to 3. client_secret : str | None An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client. client_id : int | None An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.

Client( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, rest_client: Optional[aiobungie.interfaces.rest.RESTInterface] = None, max_retries: int = 4, max_ratelimit_retries: int = 3)
102    def __init__(
103        self,
104        token: str,
105        /,
106        client_secret: typing.Optional[str] = None,
107        client_id: typing.Optional[int] = None,
108        *,
109        rest_client: typing.Optional[interfaces.RESTInterface] = None,
110        max_retries: int = 4,
111        max_ratelimit_retries: int = 3,
112    ) -> None:
113
114        self._client_secret = client_secret
115        self._client_id = client_id
116
117        self._rest = (
118            rest_client
119            if rest_client is not None
120            else rest_.RESTClient(
121                token,
122                client_secret,
123                client_id,
124                max_retries=max_retries,
125                max_ratelimit_retries=max_ratelimit_retries,
126            )
127        )
128
129        self._factory = factory_.Factory(self)

Returns the marshalling factory for the client.

rest: aiobungie.interfaces.rest.RESTInterface

Returns the REST client for the this client.

request: aiobungie.Client

A readonly ClientApp instance used for external requests.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

def run( self, future: collections.abc.Coroutine[typing.Any, None, None], debug: bool = False) -> None:
147    def run(
148        self, future: collections.Coroutine[typing.Any, None, None], debug: bool = False
149    ) -> None:
150        loop: typing.Final[asyncio.AbstractEventLoop] = helpers.get_or_make_loop()
151        try:
152            if not loop.is_running():
153                loop.set_debug(debug)
154                loop.run_until_complete(future)
155
156        except Exception as exc:
157            raise RuntimeError(f"Failed to run {future.__qualname__}") from exc
158
159        except KeyboardInterrupt:
160            _LOG.warn("Unexpected Keyboard interrupt. Exiting.")
161            return
162
163        finally:
164            if self._rest.is_alive:
165                # Clean up sessions.
166                loop.run_until_complete(self._rest.close())

Runs a coroutine function until its complete.

This is equivalent to asyncio.get_event_loop().run_until_complete(...)

Parameters
  • future (collections.Coroutine[None, None, None]): A coroutine object.
  • debug (bool): Either to enable asyncio debug or not. Disabled by default.
Example
async def main() -> None:
    await fetch(...)

# Run the coroutine.
client.run(main())
async def fetch_current_user_memberships(self, access_token: str, /) -> aiobungie.crates.user.User:
170    async def fetch_current_user_memberships(self, access_token: str, /) -> user.User:
171        """Fetch and return a user object of the bungie net user associated with account.
172
173        .. warning::
174            This method requires OAuth2 scope and a Bearer access token.
175
176        Parameters
177        ----------
178        access_token : `str`
179            A valid Bearer access token for the authorization.
180
181        Returns
182        -------
183        `aiobungie.crates.user.User`
184            A user object includes the Destiny memberships and Bungie.net user.
185        """
186        resp = await self.rest.fetch_current_user_memberships(access_token)
187
188        return self.factory.deserialize_user(resp)

Fetch and return a user object of the bungie net user associated with account.

This method requires OAuth2 scope and a Bearer access token.

Parameters
  • access_token (str): A valid Bearer access token for the authorization.
Returns
  • aiobungie.crates.user.User: A user object includes the Destiny memberships and Bungie.net user.
async def fetch_bungie_user(self, id: int, /) -> aiobungie.crates.user.BungieUser:
190    async def fetch_bungie_user(self, id: int, /) -> user.BungieUser:
191        """Fetch a Bungie user by their BungieNet id.
192
193        .. note::
194            This returns a Bungie user membership only. Take a look at `Client.fetch_membership_from_id`
195            for other memberships.
196
197        Parameters
198        ----------
199        id: `int`
200            The user id.
201
202        Returns
203        -------
204        `aiobungie.crates.user.BungieUser`
205            A Bungie user.
206
207        Raises
208        ------
209        `aiobungie.error.NotFound`
210            The user was not found.
211        """
212        payload = await self.rest.fetch_bungie_user(id)
213
214        return self.factory.deserialize_bungie_user(payload)

Fetch a Bungie user by their BungieNet id.

This returns a Bungie user membership only. Take a look at Client.fetch_membership_from_id for other memberships.

Parameters
  • id (int): The user id.
Returns
  • aiobungie.crates.user.BungieUser: A Bungie user.
Raises
async def search_users( self, name: str, /) -> aiobungie.FlatIterator[aiobungie.crates.user.SearchableDestinyUser]:
216    async def search_users(
217        self, name: str, /
218    ) -> iterators.FlatIterator[user.SearchableDestinyUser]:
219        """Search for players and return all players that matches the same name.
220
221        Parameters
222        ----------
223        name : `buildins.str`
224            The user name.
225
226        Returns
227        -------
228        `aiobungie.iterators.FlatIterator[aiobungie.crates.DestinyMembership]`
229            A sequence of destiny memberships.
230        """
231        payload = await self.rest.search_users(name)
232
233        return iterators.FlatIterator(
234            [
235                self.factory.deserialize_searched_user(user)
236                for user in payload["searchResults"]
237            ]
238        )

Search for players and return all players that matches the same name.

Parameters
  • name (buildins.str): The user name.
Returns
async def fetch_user_themes(self) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
240    async def fetch_user_themes(self) -> collections.Sequence[user.UserThemes]:
241        """Fetch all available user themes.
242
243        Returns
244        -------
245        `collections.Sequence[aiobungie.crates.user.UserThemes]`
246            A sequence of user themes.
247        """
248        data = await self.rest.fetch_user_themes()
249
250        return self.factory.deserialize_user_themes(data)

Fetch all available user themes.

Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of user themes.
async def fetch_hard_types( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> aiobungie.crates.user.HardLinkedMembership:
252    async def fetch_hard_types(
253        self,
254        credential: int,
255        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
256        /,
257    ) -> user.HardLinkedMembership:
258        """Gets any hard linked membership given a credential.
259        Only works for credentials that are public just `aiobungie.CredentialType.STEAMID` right now.
260        Cross Save aware.
261
262        Parameters
263        ----------
264        credential: `int`
265            A valid SteamID64
266        type: `aiobungie.CredentialType`
267            The credential type. This must not be changed
268            Since its only credential that works "currently"
269
270        Returns
271        -------
272        `aiobungie.crates.user.HardLinkedMembership`
273            Information about the hard linked data.
274        """
275
276        payload = await self.rest.fetch_hardlinked_credentials(credential, type)
277
278        return user.HardLinkedMembership(
279            id=int(payload["membershipId"]),
280            type=enums.MembershipType(payload["membershipType"]),
281            cross_save_type=enums.MembershipType(payload["CrossSaveOverriddenType"]),
282        )

Gets any hard linked membership given a credential. Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
  • credential (int): A valid SteamID64
  • type (aiobungie.CredentialType): The credential type. This must not be changed Since its only credential that works "currently"
Returns
  • aiobungie.crates.user.HardLinkedMembership: Information about the hard linked data.
async def fetch_membership_from_id( self, id: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.crates.user.User:
284    async def fetch_membership_from_id(
285        self,
286        id: int,
287        /,
288        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
289    ) -> user.User:
290        """Fetch Bungie user's memberships from their id.
291
292        Notes
293        -----
294        * This returns both BungieNet membership and a sequence of the player's DestinyMemberships
295        Which includes Stadia, Xbox, Steam and PSN memberships if the player has them,
296        see `aiobungie.crates.user.DestinyMembership` for more details.
297        * If you only want the bungie user. Consider using `Client.fetch_user` method.
298
299        Parameters
300        ----------
301        id : `int`
302            The user's id.
303        type : `aiobungie.MembershipType`
304            The user's membership type.
305
306        Returns
307        -------
308        `aiobungie.crates.User`
309            A Bungie user with their membership types.
310
311        Raises
312        ------
313        aiobungie.NotFound
314            The requested user was not found.
315        """
316        payload = await self.rest.fetch_membership_from_id(id, type)
317
318        return self.factory.deserialize_user(payload)

Fetch Bungie user's memberships from their id.

Notes
  • This returns both BungieNet membership and a sequence of the player's DestinyMemberships Which includes Stadia, Xbox, Steam and PSN memberships if the player has them, see aiobungie.crates.user.DestinyMembership for more details.
  • If you only want the bungie user. Consider using Client.fetch_user method.
Parameters
Returns
Raises
async def fetch_user_credentials( self, access_token: str, membership_id: int, /) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
320    async def fetch_user_credentials(
321        self, access_token: str, membership_id: int, /
322    ) -> collections.Sequence[user.UserCredentials]:
323        """Fetch an array of credential types attached to the requested account.
324
325        .. note::
326            This method require OAuth2 Bearer access token.
327
328        Parameters
329        ----------
330        access_token : `str`
331            The bearer access token associated with the bungie account.
332        membership_id : `int`
333            The id of the membership to return.
334
335        Returns
336        -------
337        `collections.Sequence[aiobungie.crates.UserCredentials]`
338            A sequence of the attached user credentials.
339
340        Raises
341        ------
342        `aiobungie.Unauthorized`
343            The access token was wrong or no access token passed.
344        """
345        resp = await self.rest.fetch_user_credentials(access_token, membership_id)
346
347        return self.factory.deserialize_user_credentials(resp)

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def fetch_profile( self, member_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.Component:
351    async def fetch_profile(
352        self,
353        member_id: int,
354        type: typedefs.IntAnd[enums.MembershipType],
355        components: list[enums.ComponentType],
356        auth: typing.Optional[str] = None,
357    ) -> components.Component:
358        """
359        Fetch a bungie profile passing components to the request.
360
361        Parameters
362        ----------
363        member_id: `int`
364            The member's id.
365        type: `aiobungie.MembershipType`
366            A valid membership type.
367        components : `list[aiobungie.ComponentType]`
368            List of profile components to collect and return.
369
370        Other Parameters
371        ----------------
372        auth : `typing.Optional[str]`
373            A Bearer access_token to make the request with.
374            This is optional and limited to components that only requires an Authorization token.
375
376        Returns
377        --------
378        `aiobungie.crates.Component`
379            A Destiny 2 player profile with its components.
380            Only passed components will be available if they exists. Otherwise they will be `None`
381
382        Raises
383        ------
384        `aiobungie.MembershipTypeError`
385            The provided membership type was invalid.
386        """
387        data = await self.rest.fetch_profile(member_id, type, components, auth)
388        return self.factory.deserialize_components(data)

Fetch a bungie profile passing components to the request.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
  • aiobungie.crates.Component: A Destiny 2 player profile with its components. Only passed components will be available if they exists. Otherwise they will be None
Raises
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> aiobungie.crates.profile.LinkedProfile:
390    async def fetch_linked_profiles(
391        self,
392        member_id: int,
393        member_type: typedefs.IntAnd[enums.MembershipType],
394        /,
395        *,
396        all: bool = False,
397    ) -> profile.LinkedProfile:
398        """Returns a summary information about all profiles linked to the requested member.
399
400        The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.
401
402        .. note::
403            It will only return linked accounts whose linkages you are allowed to view.
404
405        Parameters
406        ----------
407        member_id : `int`
408            The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
409        member_type : `aiobungie.MembershipType`
410            The type for the membership whose linked Destiny account you want to return.
411
412        Other Parameters
413        ----------------
414        all : `bool`
415            If provided and set to `True`, All memberships regardless
416            of whether they're obscured by overrides will be returned,
417
418            If provided and set to `False`, Only available memberships will be returned.
419            The default for this is `False`.
420
421        Returns
422        -------
423        `aiobungie.crates.profile.LinkedProfile`
424            A linked profile object.
425        """
426        resp = await self.rest.fetch_linked_profiles(member_id, member_type, all=all)
427
428        return self.factory.deserialize_linked_profiles(resp)

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
  • member_id (int): The ID of the membership. This must be a valid Bungie.Net or PSN or Xbox ID.
  • member_type (aiobungie.MembershipType): The type for the membership whose linked Destiny account you want to return.
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether they're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
  • aiobungie.crates.profile.LinkedProfile: A linked profile object.
async def fetch_player( self, name: str, code: int, /, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
430    async def fetch_player(
431        self,
432        name: str,
433        code: int,
434        /,
435        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
436    ) -> collections.Sequence[user.DestinyMembership]:
437        """Fetch a Destiny 2 player's memberships.
438
439        Parameters
440        -----------
441        name: `str`
442            The unique Bungie player name.
443        code : `int`
444            The unique Bungie display name code.
445        type: `aiobungie.internal.enums.MembershipType`
446            The player's membership type, e,g. XBOX, STEAM, PSN
447
448        Returns
449        --------
450        `collections.Sequence[aiobungie.crates.DestinyMembership]`
451            A sequence of the found Destiny 2 player memberships.
452            An empty sequence will be returned if no one found.
453
454        Raises
455        ------
456        `aiobungie.MembershipTypeError`
457            The provided membership type was invalid.
458        """
459        resp = await self.rest.fetch_player(name, code, type)
460
461        return self.factory.deserialize_destiny_memberships(resp)

Fetch a Destiny 2 player's memberships.

Parameters
  • name (str): The unique Bungie player name.
  • code (int): The unique Bungie display name code.
  • type (aiobungie.MembershipType): The player's membership type, e,g. XBOX, STEAM, PSN
Returns
Raises
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> aiobungie.crates.components.CharacterComponent:
463    async def fetch_character(
464        self,
465        member_id: int,
466        membership_type: typedefs.IntAnd[enums.MembershipType],
467        character_id: int,
468        components: list[enums.ComponentType],
469        auth: typing.Optional[str] = None,
470    ) -> components.CharacterComponent:
471        """Fetch a Destiny 2 character.
472
473        Parameters
474        ----------
475        member_id: `int`
476            A valid bungie member id.
477        character_id: `int`
478            The Destiny character id to retrieve.
479        membership_type: `aiobungie.internal.enums.MembershipType`
480            The member's membership type.
481        components: `list[aiobungie.ComponentType]`
482            Multiple arguments of character components to collect and return.
483
484        Other Parameters
485        ----------------
486        auth : `typing.Optional[str]`
487            A Bearer access_token to make the request with.
488            This is optional and limited to components that only requires an Authorization token.
489
490        Returns
491        -------
492        `aiobungie.crates.CharacterComponent`
493            A Bungie character component.
494
495        `aiobungie.MembershipTypeError`
496            The provided membership type was invalid.
497        """
498        resp = await self.rest.fetch_character(
499            member_id, membership_type, character_id, components, auth
500        )
501
502        return self.factory.deserialize_character_component(resp)

Fetch a Destiny 2 character.

Parameters
  • member_id (int): A valid bungie member id.
  • character_id (int): The Destiny character id to retrieve.
  • membership_type (aiobungie.MembershipType): The member's membership type.
  • components (list[aiobungie.ComponentType]): Multiple arguments of character components to collect and return.
Other Parameters
  • auth (typing.Optional[str]): A Bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> collections.abc.Sequence[aiobungie.crates.activity.ExtendedWeaponValues]:
504    async def fetch_unique_weapon_history(
505        self,
506        membership_id: int,
507        character_id: int,
508        membership_type: typedefs.IntAnd[enums.MembershipType],
509    ) -> collections.Sequence[activity.ExtendedWeaponValues]:
510        """Fetch details about unique weapon usage for a character. Includes all exotics.
511
512        Parameters
513        ----------
514        membership_id : `int`
515            The Destiny user membership id.
516        character_id : `int`
517            The character id to retrieve.
518        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
519            The Destiny user's membership type.
520
521        Returns
522        -------
523        `collections.Sequence[aiobungie.crates.ExtendedWeaponValues]`
524            A sequence of the weapon's extended values.
525        """
526        resp = await self._rest.fetch_unique_weapon_history(
527            membership_id, character_id, membership_type
528        )
529
530        return [
531            self._factory.deserialize_extended_weapon_values(weapon)
532            for weapon in resp["weapons"]
533        ]

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], *, membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, page: int = 0, limit: int = 250) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
537    async def fetch_activities(
538        self,
539        member_id: int,
540        character_id: int,
541        mode: typedefs.IntAnd[enums.GameMode],
542        *,
543        membership_type: typedefs.IntAnd[
544            enums.MembershipType
545        ] = enums.MembershipType.ALL,
546        page: int = 0,
547        limit: int = 250,
548    ) -> iterators.FlatIterator[activity.Activity]:
549        """Fetch a Destiny 2 activity for the specified character id.
550
551        Parameters
552        ----------
553        member_id: `int`
554            The user id that starts with `4611`.
555        character_id: `int`
556            The id of the character to retrieve the activities for.
557        mode: `aiobungie.typedefs.IntAnd[aiobungie.internal.enums.GameMode]`
558            This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
559
560        Other Parameters
561        ----------------
562        membership_type: `aiobungie.internal.enums.MembershipType`
563            The Member ship type, if nothing was passed than it will return all.
564        page: int
565            The page number. Default is `0`
566        limit: int
567            Limit the returned result. Default is `250`.
568
569        Returns
570        -------
571        `aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]`
572            An iterator of the player's activities.
573
574        Raises
575        ------
576        `aiobungie.MembershipTypeError`
577            The provided membership type was invalid.
578        """
579        resp = await self.rest.fetch_activities(
580            member_id,
581            character_id,
582            mode,
583            membership_type=membership_type,
584            page=page,
585            limit=limit,
586        )
587
588        return self.factory.deserialize_activities(resp)

Fetch a Destiny 2 activity for the specified character id.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve the activities for.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
  • membership_type (aiobungie.MembershipType): The Member ship type, if nothing was passed than it will return all.
  • page (int): The page number. Default is 0
  • limit (int): Limit the returned result. Default is 250.
Returns
Raises
async def fetch_post_activity(self, instance_id: int, /) -> aiobungie.crates.activity.PostActivity:
590    async def fetch_post_activity(self, instance_id: int, /) -> activity.PostActivity:
591        """Fetch a post activity details.
592
593        Parameters
594        ----------
595        instance_id: `int`
596            The activity instance id.
597
598        Returns
599        -------
600        `aiobungie.crates.PostActivity`
601           A post activity object.
602        """
603        resp = await self.rest.fetch_post_activity(instance_id)
604
605        return self.factory.deserialize_post_activity(resp)

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
607    async def fetch_aggregated_activity_stats(
608        self,
609        character_id: int,
610        membership_id: int,
611        membership_type: typedefs.IntAnd[enums.MembershipType],
612    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
613        """Fetch aggregated activity stats for a character.
614
615        Parameters
616        ----------
617        character_id: `int`
618            The id of the character to retrieve the activities for.
619        membership_id: `int`
620            The id of the user that started with `4611`.
621        membership_type: `aiobungie.internal.enums.MembershipType`
622            The Member ship type.
623
624        Returns
625        -------
626        `aiobungie.iterators.FlatIterator[aiobungie.crates.AggregatedActivity]`
627            An iterator of the player's activities.
628
629        Raises
630        ------
631        `aiobungie.MembershipTypeError`
632            The provided membership type was invalid.
633        """
634        resp = await self.rest.fetch_aggregated_activity_stats(
635            character_id, membership_id, membership_type
636        )
637
638        return self.factory.deserialize_aggregated_activities(resp)

Fetch aggregated activity stats for a character.

Parameters
  • character_id (int): The id of the character to retrieve the activities for.
  • membership_id (int): The id of the user that started with 4611.
  • membership_type (aiobungie.MembershipType): The Member ship type.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> aiobungie.crates.clans.Clan:
642    async def fetch_clan_from_id(
643        self,
644        id: int,
645        /,
646        access_token: typing.Optional[str] = None,
647    ) -> clans.Clan:
648        """Fetch a Bungie Clan by its id.
649
650        Parameters
651        -----------
652        id: `int`
653            The clan id.
654
655        Returns
656        --------
657        `aiobungie.crates.Clan`
658            An Bungie clan.
659
660        Raises
661        ------
662        `aiobungie.NotFound`
663            The clan was not found.
664        """
665        resp = await self.rest.fetch_clan_from_id(id, access_token)
666
667        return self.factory.deserialize_clan(resp)

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> aiobungie.crates.clans.Clan:
669    async def fetch_clan(
670        self,
671        name: str,
672        /,
673        access_token: typing.Optional[str] = None,
674        *,
675        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
676    ) -> clans.Clan:
677        """Fetch a Clan by its name.
678        This method will return the first clan found with given name.
679
680        Parameters
681        ----------
682        name: `str`
683            The clan name
684
685        Other Parameters
686        ----------------
687        access_token : `typing.Optional[str]`
688            An optional access token to make the request with.
689
690            If the token was bound to a member of the clan,
691            This field `aiobungie.crates.Clan.current_user_membership` will be available
692            and will return the membership of the user who made this request.
693        type : `aiobungie.GroupType`
694            The group type, Default is aiobungie.GroupType.CLAN.
695
696        Returns
697        -------
698        `aiobungie.crates.Clan`
699            A Bungie clan.
700
701        Raises
702        ------
703        `aiobungie.NotFound`
704            The clan was not found.
705        """
706        resp = await self.rest.fetch_clan(name, access_token, type=type)
707
708        return self.factory.deserialize_clan(resp)

Fetch a Clan by its name. This method will return the first clan found with given name.

Parameters
  • name (str): The clan name
Other Parameters
Returns
Raises
async def fetch_clan_conversations( self, clan_id: int, /) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
710    async def fetch_clan_conversations(
711        self, clan_id: int, /
712    ) -> collections.Sequence[clans.ClanConversation]:
713        """Fetch the conversations/chat channels of the given clan id.
714
715        Parameters
716        ----------
717        clan_id : `int`
718            The clan id.
719
720        Returns
721        `collections.Sequence[aiobungie.crates.ClanConversation]`
722            A sequence of the clan chat channels.
723        """
724        resp = await self.rest.fetch_clan_conversations(clan_id)
725
726        return self.factory.deserialize_clan_conversations(resp)

Fetch the conversations/chat channels of the given clan id.

Parameters
async def fetch_clan_admins( self, clan_id: int, /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
728    async def fetch_clan_admins(
729        self, clan_id: int, /
730    ) -> iterators.FlatIterator[clans.ClanMember]:
731        """Fetch the clan founder and admins.
732
733        Parameters
734        ----------
735        clan_id : `int`
736            The clan id.
737
738        Returns
739        -------
740        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
741            An iterator over the found clan admins and founder.
742
743        Raises
744        ------
745        `aiobungie.NotFound`
746            The requested clan was not found.
747        """
748        resp = await self.rest.fetch_clan_admins(clan_id)
749
750        return self.factory.deserialize_clan_members(resp)

Fetch the clan founder and admins.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: aiobungie.GroupType = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
752    async def fetch_groups_for_member(
753        self,
754        member_id: int,
755        member_type: typedefs.IntAnd[enums.MembershipType],
756        /,
757        *,
758        filter: int = 0,
759        group_type: enums.GroupType = enums.GroupType.CLAN,
760    ) -> collections.Sequence[clans.GroupMember]:
761        """Fetch information about the groups that a given member has joined.
762
763        Parameters
764        ----------
765        member_id : `int`
766            The member's id
767        member_type : `aiobungie.MembershipType`
768            The member's membership type.
769
770        Other Parameters
771        ----------------
772        filter : `int`
773            Filter apply to list of joined groups. This Default to `0`
774        group_type : `aiobungie.GroupType`
775            The group's type.
776            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
777
778        Returns
779        -------
780        `collections.Sequence[aiobungie.crates.GroupMember]`
781            A sequence of joined groups for the fetched member.
782        """
783        resp = await self.rest.fetch_groups_for_member(
784            member_id, member_type, filter=filter, group_type=group_type
785        )
786
787        return [
788            self.factory.deserialize_group_member(group) for group in resp["results"]
789        ]

Fetch information about the groups that a given member has joined.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> collections.abc.Sequence[aiobungie.crates.clans.GroupMember]:
791    async def fetch_potential_groups_for_member(
792        self,
793        member_id: int,
794        member_type: typedefs.IntAnd[enums.MembershipType],
795        /,
796        *,
797        filter: int = 0,
798        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
799    ) -> collections.Sequence[clans.GroupMember]:
800        """Fetch the potential groups for a clan member.
801
802        Parameters
803        ----------
804        member_id : `int`
805            The member's id
806        member_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
807            The member's membership type.
808
809        Other Parameters
810        ----------------
811        filter : `int`
812            Filter apply to list of joined groups. This Default to `0`
813        group_type : `aiobungie.typedefs.IntAnd[aiobungie.GroupType]`
814            The group's type.
815            This is always set to `aiobungie.GroupType.CLAN` and should not be changed.
816
817        Returns
818        -------
819        `collections.Sequence[aiobungie.crates.GroupMember]`
820            A sequence of joined potential groups for the fetched member.
821        """
822        resp = await self.rest.fetch_potential_groups_for_member(
823            member_id, member_type, filter=filter, group_type=group_type
824        )
825
826        return [
827            self.factory.deserialize_group_member(group) for group in resp["results"]
828        ]

Fetch the potential groups for a clan member.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
830    async def fetch_clan_members(
831        self,
832        clan_id: int,
833        /,
834        *,
835        name: typing.Optional[str] = None,
836        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
837    ) -> iterators.FlatIterator[clans.ClanMember]:
838        """Fetch Bungie clan members.
839
840        Parameters
841        ----------
842        clan_id : `int`
843            The clans id
844
845        Other Parameters
846        ----------------
847        name : `typing.Optional[str]`
848            If provided, Only players matching this name will be returned.
849        type : `aiobungie.MembershipType`
850            An optional clan member's membership type.
851            This parameter is used to filter the returned results
852            by the provided membership, For an example XBox memberships only,
853            Otherwise will return all memberships.
854
855        Returns
856        -------
857        `aiobungie.iterators.FlatIterator[aiobungie.crates.ClanMember]`
858            An iterator over the bungie clan members.
859
860        Raises
861        ------
862        `aiobungie.NotFound`
863            The clan was not found.
864        """
865        resp = await self.rest.fetch_clan_members(clan_id, type=type, name=name)
866
867        return self.factory.deserialize_clan_members(resp)

Fetch Bungie clan members.

Parameters
  • clan_id (int): The clans id
Other Parameters
  • name (typing.Optional[str]): If provided, Only players matching this name will be returned.
  • type (aiobungie.MembershipType): An optional clan member's membership type. This parameter is used to filter the returned results by the provided membership, For an example XBox memberships only, Otherwise will return all memberships.
Returns
Raises
async def fetch_clan_banners(self) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
869    async def fetch_clan_banners(self) -> collections.Sequence[clans.ClanBanner]:
870        """Fetch the clan banners.
871
872        Returns
873        -------
874        `collections.Sequence[aiobungie.crates.ClanBanner]`
875            A sequence of the clan banners.
876        """
877        resp = await self.rest.fetch_clan_banners()
878
879        return self.factory.deserialize_clan_banners(resp)

Fetch the clan banners.

Returns
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> aiobungie.crates.clans.Clan:
882    async def kick_clan_member(
883        self,
884        access_token: str,
885        /,
886        group_id: int,
887        membership_id: int,
888        membership_type: typedefs.IntAnd[enums.MembershipType],
889    ) -> clans.Clan:
890        """Kick a member from the clan.
891
892        .. note::
893            This request requires OAuth2: oauth2: `AdminGroups` scope.
894
895        Parameters
896        ----------
897        access_token : `str`
898            The bearer access token associated with the bungie account.
899        group_id: `int`
900            The group id.
901        membership_id : `int`
902            The member id to kick.
903        membership_type : `aiobungie.typedefs.IntAnd[aiobungie.MembershipType]`
904            The member's membership type.
905
906        Returns
907        -------
908        `aiobungie.crates.clan.Clan`
909            The clan that the member was kicked from.
910        """
911        resp = await self.rest.kick_clan_member(
912            access_token,
913            group_id=group_id,
914            membership_id=membership_id,
915            membership_type=membership_type,
916        )
917
918        return self.factory.deserialize_clan(resp)

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
  • aiobungie.crates.clan.Clan: The clan that the member was kicked from.
async def fetch_clan_weekly_rewards(self, clan_id: int) -> aiobungie.crates.milestones.Milestone:
920    async def fetch_clan_weekly_rewards(self, clan_id: int) -> milestones.Milestone:
921        """Fetch a Bungie clan's weekly reward state.
922
923        Parameters
924        ----------
925        clan_id : `int`
926            The clan's id.
927
928        Returns
929        -------
930        `aiobungie.crates.Milestone`
931            A runtime status of the clan's milestone data.
932        """
933
934        resp = await self.rest.fetch_clan_weekly_rewards(clan_id)
935
936        return self.factory.deserialize_milestone(resp)

Fetch a Bungie clan's weekly reward state.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_inventory_item(self, hash: int, /) -> aiobungie.crates.entity.InventoryEntity:
940    async def fetch_inventory_item(self, hash: int, /) -> entity.InventoryEntity:
941        """Fetch a static inventory item entity given a its hash.
942
943        Parameters
944        ----------
945        hash: `int`
946            Inventory item's hash.
947
948        Returns
949        -------
950        `aiobungie.crates.InventoryEntity`
951            A bungie inventory item.
952        """
953        resp = await self.rest.fetch_inventory_item(hash)
954
955        return self.factory.deserialize_inventory_entity(resp)

Fetch a static inventory item entity given a its hash.

Parameters
  • hash (int): Inventory item's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> aiobungie.crates.entity.ObjectiveEntity:
957    async def fetch_objective_entity(self, hash: int, /) -> entity.ObjectiveEntity:
958        """Fetch a Destiny objective entity given a its hash.
959
960        Parameters
961        ----------
962        hash: `int`
963            objective's hash.
964
965        Returns
966        -------
967        `aiobungie.crates.ObjectiveEntity`
968            An objective entity item.
969        """
970        resp = await self.rest.fetch_objective_entity(hash)
971
972        return self.factory.deserialize_objective_entity(resp)

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
974    async def search_entities(
975        self, name: str, entity_type: str, *, page: int = 0
976    ) -> iterators.FlatIterator[entity.SearchableEntity]:
977        """Search for Destiny2 entities given a name and its type.
978
979        Parameters
980        ----------
981        name : `str`
982            The name of the entity, i.e., Thunderlord, One thousand voices.
983        entity_type : `str`
984            The type of the entity, AKA Definition,
985            For an example `DestinyInventoryItemDefinition` for emblems, weapons, and other inventory items.
986
987        Other Parameters
988        ----------------
989        page : `int`
990            An optional page to return. Default to 0.
991
992        Returns
993        -------
994        `aiobungie.iterators.FlatIterator[aiobungie.crates.SearchableEntity]`
995            An iterator over the found results matching the provided name.
996        """
997        resp = await self.rest.search_entities(name, entity_type, page=page)
998
999        return self.factory.deserialize_inventory_results(resp)

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition for emblems, weapons, and other inventory items.
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: int = 0, page: int = 0, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1003    async def fetch_fireteams(
1004        self,
1005        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1006        *,
1007        platform: typedefs.IntAnd[
1008            fireteams.FireteamPlatform
1009        ] = fireteams.FireteamPlatform.ANY,
1010        language: typing.Union[
1011            fireteams.FireteamLanguage, str
1012        ] = fireteams.FireteamLanguage.ALL,
1013        date_range: int = 0,
1014        page: int = 0,
1015        slots_filter: int = 0,
1016    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1017        """Fetch public Bungie fireteams with open slots.
1018
1019        Parameters
1020        ----------
1021        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1022            The fireteam activity type.
1023
1024        Other Parameters
1025        ----------------
1026        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1027            If this is provided. Then the results will be filtered with the given platform.
1028            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1029        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1030            A locale language to filter the used language in that fireteam.
1031            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1032        date_range : `int`
1033            An integer to filter the date range of the returned fireteams. Defaults to `aiobungie.FireteamDate.ALL`.
1034        page : `int`
1035            The page number. By default its `0` which returns all available activities.
1036        slots_filter : `int`
1037            Filter the returned fireteams based on available slots. Default is `0`
1038
1039        Returns
1040        -------
1041        `typing.Optional[collections.Sequence[fireteams.Fireteam]]`
1042            A sequence of `aiobungie.crates.Fireteam` or `None`.
1043        """
1044
1045        resp = await self.rest.fetch_fireteams(
1046            activity_type,
1047            platform=platform,
1048            language=language,
1049            date_range=date_range,
1050            page=page,
1051            slots_filter=slots_filter,
1052        )
1053
1054        return self.factory.deserialize_fireteams(resp)

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: int = 0, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
1056    async def fetch_avaliable_clan_fireteams(
1057        self,
1058        access_token: str,
1059        group_id: int,
1060        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1061        *,
1062        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1063        language: typing.Union[fireteams.FireteamLanguage, str],
1064        date_range: int = 0,
1065        page: int = 0,
1066        public_only: bool = False,
1067        slots_filter: int = 0,
1068    ) -> typing.Optional[collections.Sequence[fireteams.Fireteam]]:
1069        """Fetch a clan's fireteams with open slots.
1070
1071        .. note::
1072            This method requires OAuth2: ReadGroups scope.
1073
1074        Parameters
1075        ----------
1076        access_token : `str`
1077            The bearer access token associated with the bungie account.
1078        group_id : `int`
1079            The group/clan id of the fireteam.
1080        activity_type : `aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]`
1081            The fireteam activity type.
1082
1083        Other Parameters
1084        ----------------
1085        platform : `aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]`
1086            If this is provided. Then the results will be filtered with the given platform.
1087            Defaults to `aiobungie.crates.FireteamPlatform.ANY` which returns all platforms.
1088        language : `typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]`
1089            A locale language to filter the used language in that fireteam.
1090            Defaults to `aiobungie.crates.FireteamLanguage.ALL`
1091        date_range : `int`
1092            An integer to filter the date range of the returned fireteams. Defaults to `0`.
1093        page : `int`
1094            The page number. By default its `0` which returns all available activities.
1095        public_only: `bool`
1096            If set to True, Then only public fireteams will be returned.
1097        slots_filter : `int`
1098            Filter the returned fireteams based on available slots. Default is `0`
1099
1100        Returns
1101        -------
1102        `typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]`
1103            A sequence of  fireteams found in the clan.
1104            `None` will be returned if nothing was found.
1105        """
1106        resp = await self.rest.fetch_avaliable_clan_fireteams(
1107            access_token,
1108            group_id,
1109            activity_type,
1110            platform=platform,
1111            language=language,
1112            date_range=date_range,
1113            page=page,
1114            public_only=public_only,
1115            slots_filter=slots_filter,
1116        )
1117
1118        return self.factory.deserialize_fireteams(resp)

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (int): An integer to filter the date range of the returned fireteams. Defaults to 0.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
  • typing.Optional[collections.Sequence[aiobungie.crates.Fireteam]]: A sequence of fireteams found in the clan. None will be returned if nothing was found.
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> aiobungie.crates.fireteams.AvailableFireteam:
1120    async def fetch_clan_fireteam(
1121        self, access_token: str, fireteam_id: int, group_id: int
1122    ) -> fireteams.AvailableFireteam:
1123        """Fetch a specific clan fireteam.
1124
1125        .. note::
1126            This method requires OAuth2: ReadGroups scope.
1127
1128        Parameters
1129        ----------
1130        access_token : `str`
1131            The bearer access token associated with the bungie account.
1132        group_id : `int`
1133            The group/clan id to fetch the fireteam from.
1134        fireteam_id : `int`
1135            The fireteam id to fetch.
1136
1137        Returns
1138        -------
1139        `typing.Optional[aiobungie.crates.AvailableFireteam]`
1140            A sequence of available fireteams objects if exists. else `None` will be returned.
1141        """
1142        resp = await self.rest.fetch_clan_fireteam(access_token, fireteam_id, group_id)
1143
1144        return self.factory.deserialize_available_fireteams(
1145            resp, no_results=True
1146        )  # type: ignore[return-value]

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]:
1148    async def fetch_my_clan_fireteams(
1149        self,
1150        access_token: str,
1151        group_id: int,
1152        *,
1153        include_closed: bool = True,
1154        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1155        language: typing.Union[fireteams.FireteamLanguage, str],
1156        filtered: bool = True,
1157        page: int = 0,
1158    ) -> collections.Sequence[fireteams.AvailableFireteam]:
1159        """A method that's similar to `fetch_fireteams` but requires OAuth2.
1160
1161        .. note::
1162            This method requires OAuth2: ReadGroups scope.
1163
1164        Parameters
1165        ----------
1166        access_token : str
1167            The bearer access token associated with the bungie account.
1168        group_id : int
1169            The group/clan id to fetch.
1170
1171        Other Parameters
1172        ----------------
1173        include_closed : bool
1174            If provided and set to True, It will also return closed fireteams.
1175            If provided and set to False, It will only return public fireteams. Default is True.
1176        platform : aiobungie.typedefs.IntAnd[aiobungie.crates.fireteams.FireteamPlatform]
1177            If this is provided. Then the results will be filtered with the given platform.
1178            Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
1179        language : typing.Union[aiobungie.crates.fireteams.FireteamLanguage, str]
1180            A locale language to filter the used language in that fireteam.
1181            Defaults to aiobungie.crates.FireteamLanguage.ALL
1182        filtered : bool
1183            If set to True, it will filter by clan. Otherwise not. Default is True.
1184        page : int
1185            The page number. By default its 0 which returns all available activities.
1186
1187        Returns
1188        -------
1189        `collections.Sequence[aiobungie.crates.AvailableFireteam]`
1190            A sequence of available fireteams objects if exists. else `None` will be returned.
1191        """
1192        resp = await self.rest.fetch_my_clan_fireteams(
1193            access_token,
1194            group_id,
1195            include_closed=include_closed,
1196            platform=platform,
1197            language=language,
1198            filtered=filtered,
1199            page=page,
1200        )
1201
1202        return self.factory.deserialize_available_fireteams(resp)  # type: ignore[return-value]

A method that's similar to fetch_fireteams but requires OAuth2.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_friends( self, access_token: str, /) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
1206    async def fetch_friends(
1207        self, access_token: str, /
1208    ) -> collections.Sequence[friends.Friend]:
1209        """Fetch bungie friend list.
1210
1211        .. note::
1212            This requests OAuth2: ReadUserData scope.
1213
1214        Parameters
1215        -----------
1216        access_token : `str`
1217            The bearer access token associated with the bungie account.
1218
1219        Returns
1220        -------
1221        `collections.Sequence[aiobungie.crates.Friend]`
1222            A sequence of the friends associated with that access token.
1223        """
1224
1225        resp = await self.rest.fetch_friends(access_token)
1226
1227        return self.factory.deserialize_friends(resp)

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> aiobungie.crates.friends.FriendRequestView:
1229    async def fetch_friend_requests(
1230        self, access_token: str, /
1231    ) -> friends.FriendRequestView:
1232        """Fetch pending bungie friend requests queue.
1233
1234        .. note::
1235            This requests OAuth2: ReadUserData scope.
1236
1237        Parameters
1238        -----------
1239        access_token : `str`
1240            The bearer access token associated with the bungie account.
1241
1242        Returns
1243        -------
1244        `aiobungie.crates.FriendRequestView`
1245            A friend requests view of that associated access token.
1246        """
1247
1248        resp = await self.rest.fetch_friend_requests(access_token)
1249
1250        return self.factory.deserialize_friend_requests(resp)

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_application(self, appid: int, /) -> aiobungie.crates.application.Application:
1254    async def fetch_application(self, appid: int, /) -> application.Application:
1255        """Fetch a Bungie application.
1256
1257        Parameters
1258        -----------
1259        appid: `int`
1260            The application id.
1261
1262        Returns
1263        --------
1264        `aiobungie.crates.Application`
1265            A Bungie application.
1266        """
1267        resp = await self.rest.fetch_application(appid)
1268
1269        return self.factory.deserialize_app(resp)

Fetch a Bungie application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_public_milestone_content( self, milestone_hash: int, /) -> aiobungie.crates.milestones.MilestoneContent:
1273    async def fetch_public_milestone_content(
1274        self, milestone_hash: int, /
1275    ) -> milestones.MilestoneContent:
1276        """Fetch the milestone content given its hash.
1277
1278        Parameters
1279        ----------
1280        milestone_hash : `int`
1281            The milestone hash.
1282
1283        Returns
1284        -------
1285        `aiobungie.crates.milestones.MilestoneContent`
1286            A milestone content object.
1287        """
1288        resp = await self.rest.fetch_public_milestone_content(milestone_hash)
1289
1290        return self.factory.deserialize_public_milestone_content(resp)

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
  • aiobungie.crates.milestones.MilestoneContent: A milestone content object.
@typing.final
class ClosedReasons(aiobungie.Flag):
782@typing.final
783class ClosedReasons(Flag):
784    """A Flags enumeration representing the reasons why a person can't join this user's fireteam."""
785
786    NONE = 0
787    MATCHMAKING = 1
788    LOADING = 2
789    SOLO = 4
790    """The activity is required to be played solo."""
791    INTERNAL_REASONS = 8
792    """
793    The user can't be joined for one of a variety of internal reasons.
794    Basically, the game can't let you join at this time,
795    but for reasons that aren't under the control of this user
796    """
797    DISALLOWED_BY_GAME_STATE = 16
798    """The user's current activity/quest/other transitory game state is preventing joining."""
799    OFFLINE = 32768
800    """The user appears offline."""

A Flags enumeration representing the reasons why a person can't join this user's fireteam.

NONE = <ClosedReasons.NONE: 0>
MATCHMAKING = <ClosedReasons.MATCHMAKING: 1>
LOADING = <ClosedReasons.LOADING: 2>
SOLO = <ClosedReasons.SOLO: 4>

The activity is required to be played solo.

INTERNAL_REASONS = <ClosedReasons.INTERNAL_REASONS: 8>

The user can't be joined for one of a variety of internal reasons. Basically, the game can't let you join at this time, but for reasons that aren't under the control of this user

DISALLOWED_BY_GAME_STATE = <ClosedReasons.DISALLOWED_BY_GAME_STATE: 16>

The user's current activity/quest/other transitory game state is preventing joining.

OFFLINE = <ClosedReasons.OFFLINE: 32768>

The user appears offline.

Inherited Members
Flag
name
value
@typing.final
class ComponentFields(aiobungie.Enum):
74@typing.final
75class ComponentFields(enums.Enum):
76    """An enum that provides fields found in a base component response."""
77
78    PRIVACY = ComponentPrivacy
79    DISABLED = False

An enum that provides fields found in a base component response.

PRIVACY = <ComponentFields.PRIVACY: <enum 'ComponentPrivacy'>>
DISABLED = <ComponentFields.DISABLED: False>
Inherited Members
Enum
name
value
@typing.final
class ComponentPrivacy(builtins.int, aiobungie.Enum):
65@typing.final
66class ComponentPrivacy(int, enums.Enum):
67    """An enum the provides privacy settings for profile components."""
68
69    NONE = 0
70    PUBLIC = 1
71    PRIVATE = 2

An enum the provides privacy settings for profile components.

NONE = <ComponentPrivacy.NONE: 0>
PUBLIC = <ComponentPrivacy.PUBLIC: 1>
PRIVATE = <ComponentPrivacy.PRIVATE: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ComponentType(aiobungie.Enum):
363@typing.final
364class ComponentType(Enum):
365    """An Enum for Destiny 2 profile Components."""
366
367    NONE = 0
368
369    PROFILE = 100
370    PROFILE_INVENTORIES = 102
371    PROFILE_CURRENCIES = 103
372    PROFILE_PROGRESSION = 104
373    ALL_PROFILES = (
374        PROFILE,
375        PROFILE_INVENTORIES,
376        PROFILE_CURRENCIES,
377        PROFILE_PROGRESSION,
378    )
379    """All profile components."""
380
381    VENDORS = 400
382    VENDOR_SALES = 402
383    VENDOR_RECEIPTS = 101
384    ALL_VENDORS = (VENDORS, VENDOR_RECEIPTS, VENDOR_SALES)
385    """All vendor components."""
386
387    # Items
388    ITEM_INSTANCES = 300
389    ITEM_OBJECTIVES = 301
390    ITEM_PERKS = 302
391    ITEM_RENDER_DATA = 303
392    ITEM_STATS = 304
393    ITEM_SOCKETS = 305
394    ITEM_TALENT_GRINDS = 306
395    ITEM_PLUG_STATES = 308
396    ITEM_PLUG_OBJECTIVES = 309
397    ITEM_REUSABLE_PLUGS = 310
398
399    ALL_ITEMS = (
400        ITEM_PLUG_OBJECTIVES,
401        ITEM_PLUG_STATES,
402        ITEM_SOCKETS,
403        ITEM_INSTANCES,
404        ITEM_OBJECTIVES,
405        ITEM_PERKS,
406        ITEM_RENDER_DATA,
407        ITEM_STATS,
408        ITEM_TALENT_GRINDS,
409        ITEM_REUSABLE_PLUGS,
410    )
411    """All item components."""
412
413    PLATFORM_SILVER = 105
414    KIOSKS = 500
415    CURRENCY_LOOKUPS = 600
416    PRESENTATION_NODES = 700
417    COLLECTIBLES = 800
418    RECORDS = 900
419    TRANSITORY = 1000
420    METRICS = 1100
421    INVENTORIES = 102
422    STRING_VARIABLES = 1200
423    CRAFTABLES = 1300
424
425    CHARACTERS = 200
426    CHARACTER_INVENTORY = 201
427    CHARECTER_PROGRESSION = 202
428    CHARACTER_RENDER_DATA = 203
429    CHARACTER_ACTIVITIES = 204
430    CHARACTER_EQUIPMENT = 205
431
432    ALL_CHARACTERS = (
433        CHARACTERS,
434        CHARACTER_INVENTORY,
435        CHARECTER_PROGRESSION,
436        CHARACTER_RENDER_DATA,
437        CHARACTER_ACTIVITIES,
438        CHARACTER_EQUIPMENT,
439        RECORDS,
440    )
441    """All character components."""
442
443    ALL = (
444        *ALL_PROFILES,  # type: ignore
445        *ALL_CHARACTERS,  # type: ignore
446        *ALL_VENDORS,  # type: ignore
447        *ALL_ITEMS,  # type: ignore
448        RECORDS,
449        CURRENCY_LOOKUPS,
450        PRESENTATION_NODES,
451        COLLECTIBLES,
452        KIOSKS,
453        METRICS,
454        PLATFORM_SILVER,
455        INVENTORIES,
456        STRING_VARIABLES,
457        TRANSITORY,
458        CRAFTABLES,
459    )
460    """ALl components included."""

An Enum for Destiny 2 profile Components.

NONE = <ComponentType.NONE: 0>
PROFILE = <ComponentType.PROFILE: 100>
PROFILE_INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
PROFILE_CURRENCIES = <ComponentType.PROFILE_CURRENCIES: 103>
PROFILE_PROGRESSION = <ComponentType.PROFILE_PROGRESSION: 104>
ALL_PROFILES = <ComponentType.ALL_PROFILES: (100, 102, 103, 104)>

All profile components.

VENDORS = <ComponentType.VENDORS: 400>
VENDOR_SALES = <ComponentType.VENDOR_SALES: 402>
VENDOR_RECEIPTS = <ComponentType.VENDOR_RECEIPTS: 101>
ALL_VENDORS = <ComponentType.ALL_VENDORS: (400, 101, 402)>

All vendor components.

ITEM_INSTANCES = <ComponentType.ITEM_INSTANCES: 300>
ITEM_OBJECTIVES = <ComponentType.ITEM_OBJECTIVES: 301>
ITEM_PERKS = <ComponentType.ITEM_PERKS: 302>
ITEM_RENDER_DATA = <ComponentType.ITEM_RENDER_DATA: 303>
ITEM_STATS = <ComponentType.ITEM_STATS: 304>
ITEM_SOCKETS = <ComponentType.ITEM_SOCKETS: 305>
ITEM_TALENT_GRINDS = <ComponentType.ITEM_TALENT_GRINDS: 306>
ITEM_PLUG_STATES = <ComponentType.ITEM_PLUG_STATES: 308>
ITEM_PLUG_OBJECTIVES = <ComponentType.ITEM_PLUG_OBJECTIVES: 309>
ITEM_REUSABLE_PLUGS = <ComponentType.ITEM_REUSABLE_PLUGS: 310>
ALL_ITEMS = <ComponentType.ALL_ITEMS: (309, 308, 305, 300, 301, 302, 303, 304, 306, 310)>

All item components.

PLATFORM_SILVER = <ComponentType.PLATFORM_SILVER: 105>
KIOSKS = <ComponentType.KIOSKS: 500>
CURRENCY_LOOKUPS = <ComponentType.CURRENCY_LOOKUPS: 600>
PRESENTATION_NODES = <ComponentType.PRESENTATION_NODES: 700>
COLLECTIBLES = <ComponentType.COLLECTIBLES: 800>
RECORDS = <ComponentType.RECORDS: 900>
TRANSITORY = <ComponentType.TRANSITORY: 1000>
METRICS = <ComponentType.METRICS: 1100>
INVENTORIES = <ComponentType.PROFILE_INVENTORIES: 102>
STRING_VARIABLES = <ComponentType.STRING_VARIABLES: 1200>
CRAFTABLES = <ComponentType.CRAFTABLES: 1300>
CHARACTERS = <ComponentType.CHARACTERS: 200>
CHARACTER_INVENTORY = <ComponentType.CHARACTER_INVENTORY: 201>
CHARECTER_PROGRESSION = <ComponentType.CHARECTER_PROGRESSION: 202>
CHARACTER_RENDER_DATA = <ComponentType.CHARACTER_RENDER_DATA: 203>
CHARACTER_ACTIVITIES = <ComponentType.CHARACTER_ACTIVITIES: 204>
CHARACTER_EQUIPMENT = <ComponentType.CHARACTER_EQUIPMENT: 205>
ALL_CHARACTERS = <ComponentType.ALL_CHARACTERS: (200, 201, 202, 203, 204, 205, 900)>

All character components.

ALL = <ComponentType.ALL: (100, 102, 103, 104, 200, 201, 202, 203, 204, 205, 900, 400, 101, 402, 309, 308, 305, 300, 301, 302, 303, 304, 306, 310, 900, 600, 700, 800, 500, 1100, 105, 102, 1200, 1000, 1300)>

ALl components included.

Inherited Members
Enum
name
value
@typing.final
class CredentialType(builtins.int, aiobungie.Enum):
664@typing.final
665class CredentialType(int, Enum):
666    """The types of the accounts system supports at bungie."""
667
668    NONE = 0
669    XUID = 1
670    PSNID = 2
671    WILD = 3
672    FAKE = 4
673    FACEBOOK = 5
674    GOOGLE = 8
675    WINDOWS = 9
676    DEMONID = 10
677    STEAMID = 12
678    BATTLENETID = 14
679    STADIAID = 16
680    TWITCHID = 18

The types of the accounts system supports at bungie.

NONE = <CredentialType.NONE: 0>
XUID = <CredentialType.XUID: 1>
PSNID = <CredentialType.PSNID: 2>
WILD = <CredentialType.WILD: 3>
FAKE = <CredentialType.FAKE: 4>
FACEBOOK = <CredentialType.FACEBOOK: 5>
GOOGLE = <CredentialType.GOOGLE: 8>
WINDOWS = <CredentialType.WINDOWS: 9>
DEMONID = <CredentialType.DEMONID: 10>
STEAMID = <CredentialType.STEAMID: 12>
BATTLENETID = <CredentialType.BATTLENETID: 14>
STADIAID = <CredentialType.STADIAID: 16>
TWITCHID = <CredentialType.TWITCHID: 18>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class DamageType(builtins.int, aiobungie.Enum):
542@typing.final
543class DamageType(int, Enum):
544    """Enums for Destiny Damage types"""
545
546    NONE = 0
547    KINETIC = 1
548    ARC = 2
549    SOLAR = 3
550    VOID = 4
551    RAID = 5
552    """This is a special damage type reserved for some raid activity encounters."""
553    STASIS = 6

Enums for Destiny Damage types

NONE = <DamageType.NONE: 0>
KINETIC = <DamageType.KINETIC: 1>
ARC = <DamageType.ARC: 2>
SOLAR = <DamageType.SOLAR: 3>
VOID = <DamageType.VOID: 4>
RAID = <DamageType.RAID: 5>

This is a special damage type reserved for some raid activity encounters.

STASIS = <DamageType.STASIS: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Difficulty(builtins.int, aiobungie.Enum):
65@typing.final
66class Difficulty(int, enums.Enum):
67    """An enum for activities difficulties."""
68
69    TRIVIAL = 0
70    EASY = 1
71    NORMAL = 2
72    CHALLENGING = 3
73    HARD = 4
74    BRAVE = 5
75    ALMOST_IMPOSSIBLE = 6
76    IMPOSSIBLE = 7

An enum for activities difficulties.

TRIVIAL = <Difficulty.TRIVIAL: 0>
EASY = <Difficulty.EASY: 1>
NORMAL = <Difficulty.NORMAL: 2>
CHALLENGING = <Difficulty.CHALLENGING: 3>
HARD = <Difficulty.HARD: 4>
BRAVE = <Difficulty.BRAVE: 5>
ALMOST_IMPOSSIBLE = <Difficulty.ALMOST_IMPOSSIBLE: 6>
IMPOSSIBLE = <Difficulty.IMPOSSIBLE: 7>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Dungeon(builtins.int, aiobungie.Enum):
165@typing.final
166class Dungeon(int, Enum):
167    """An Enum for all available Dungeon/Like missions in Destiny 2."""
168
169    NORMAL_PRESAGE = 2124066889
170    """Normal Presage"""
171
172    MASTER_PRESAGE = 4212753278
173    """Master Presage"""
174
175    HARBINGER = 1738383283
176    """Harbinger"""
177
178    PROPHECY = 4148187374
179    """Prophecy"""
180
181    MASTER_POH = 785700673
182    """Master Pit of Heresy?"""
183
184    LEGEND_POH = 785700678
185    """Legend Pit of Heresy?"""
186
187    POH = 1375089621
188    """Normal Pit of Heresy."""
189
190    SHATTERED = 2032534090
191    """Shattered Throne"""
192
193    GOA_LEGEND = 4078656646
194    """Grasp of Avarice legend."""
195
196    GOA_MASTER = 3774021532
197    """Grasp of Avarice master."""

An Enum for all available Dungeon/Like missions in Destiny 2.

NORMAL_PRESAGE = <Dungeon.NORMAL_PRESAGE: 2124066889>

Normal Presage

MASTER_PRESAGE = <Dungeon.MASTER_PRESAGE: 4212753278>

Master Presage

HARBINGER = <Dungeon.HARBINGER: 1738383283>

Harbinger

PROPHECY = <Dungeon.PROPHECY: 4148187374>

Prophecy

MASTER_POH = <Dungeon.MASTER_POH: 785700673>

Master Pit of Heresy?

LEGEND_POH = <Dungeon.LEGEND_POH: 785700678>

Legend Pit of Heresy?

POH = <Dungeon.POH: 1375089621>

Normal Pit of Heresy.

SHATTERED = <Dungeon.SHATTERED: 2032534090>

Shattered Throne

GOA_LEGEND = <Dungeon.GOA_LEGEND: 4078656646>

Grasp of Avarice legend.

GOA_MASTER = <Dungeon.GOA_MASTER: 3774021532>

Grasp of Avarice master.

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Enum(enum.Enum):
77class Enum(__enum.Enum):
78    """Builtin Python enum with extra handlings."""
79
80    @property
81    def name(self) -> str:  # type: ignore[override]
82        return self._name_
83
84    @property
85    def value(self) -> typing.Any:  # type: ignore[override]
86        return self._value_
87
88    def __str__(self) -> str:
89        return self._name_
90
91    def __repr__(self) -> str:
92        return f"<{type(self).__name__}.{self._name_}: {self._value_!s}>"
93
94    def __int__(self) -> int:
95        if isinstance(self.value, _ITERABLE):
96            raise TypeError(
97                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
98            )
99        return int(self.value)

Builtin Python enum with extra handlings.

name: str
value: Any
class Factory(aiobungie.interfaces.factory.FactoryInterface):
  61class Factory(interfaces.FactoryInterface):
  62    """The base deserialization factory class for all aiobungie objects.
  63
  64    Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them
  65    into a `aiobungie.crates` Python classes.
  66    """
  67
  68    __slots__ = ("_net",)
  69
  70    def __init__(self, net: traits.Netrunner) -> None:
  71        self._net = net
  72
  73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
  74        return user.BungieUser(
  75            id=int(data["membershipId"]),
  76            created_at=time.clean_date(data["firstAccess"]),
  77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
  78            is_deleted=data["isDeleted"],
  79            about=data["about"],
  80            updated_at=time.clean_date(data["lastUpdate"]),
  81            psn_name=data.get("psnDisplayName", None),
  82            stadia_name=data.get("stadiaDisplayName", None),
  83            steam_name=data.get("steamDisplayName", None),
  84            twitch_name=data.get("twitchDisplayName", None),
  85            blizzard_name=data.get("blizzardDisplayName", None),
  86            status=data["statusText"],
  87            locale=data["locale"],
  88            picture=assets.Image(path=str(data["profilePicturePath"])),
  89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
  90            unique_name=data.get("uniqueName", None),
  91            theme_id=int(data["profileTheme"]),
  92            show_activity=bool(data["showActivity"]),
  93            theme_name=data["profileThemeName"],
  94            display_title=data["userTitleDisplay"],
  95        )
  96
  97    def deserialize_partial_bungie_user(
  98        self, payload: typedefs.JSONObject
  99    ) -> user.PartialBungieUser:
 100        return user.PartialBungieUser(
 101            net=self._net,
 102            types=[
 103                enums.MembershipType(type_)
 104                for type_ in payload.get("applicableMembershipTypes", [])
 105            ],
 106            name=payload.get("displayName", undefined.Undefined),
 107            id=int(payload["membershipId"]),
 108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 109            is_public=payload["isPublic"],
 110            icon=assets.Image(payload.get("iconPath", "")),
 111            type=enums.MembershipType(payload["membershipType"]),
 112        )
 113
 114    def deserialize_destiny_membership(
 115        self, payload: typedefs.JSONObject
 116    ) -> user.DestinyMembership:
 117        name: undefined.UndefinedOr[str] = undefined.Undefined
 118        if (
 119            raw_name := payload.get("bungieGlobalDisplayName", "")
 120        ) and not typedefs.is_unknown(raw_name):
 121            name = raw_name
 122
 123        return user.DestinyMembership(
 124            net=self._net,
 125            id=int(payload["membershipId"]),
 126            name=name,
 127            code=payload.get("bungieGlobalDisplayNameCode", None),
 128            last_seen_name=payload.get("LastSeenDisplayName")
 129            or payload.get("displayName")  # noqa: W503
 130            or "",  # noqa: W503
 131            type=enums.MembershipType(payload["membershipType"]),
 132            is_public=payload["isPublic"],
 133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
 134            icon=assets.Image(payload.get("iconPath", "")),
 135            types=[
 136                enums.MembershipType(type_)
 137                for type_ in payload.get("applicableMembershipTypes", [])
 138            ],
 139        )
 140
 141    def deserialize_destiny_memberships(
 142        self, data: typedefs.JSONArray
 143    ) -> collections.Sequence[user.DestinyMembership]:
 144        return [self.deserialize_destiny_membership(membership) for membership in data]
 145
 146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
 147
 148        primary_membership_id: typing.Optional[int] = None
 149        if raw_primary_id := data.get("primaryMembershipId"):
 150            primary_membership_id = int(raw_primary_id)
 151
 152        return user.User(
 153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
 154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
 155            primary_membership_id=primary_membership_id,
 156        )
 157
 158    def deserialize_searched_user(
 159        self, payload: typedefs.JSONObject
 160    ) -> user.SearchableDestinyUser:
 161        name: undefined.UndefinedOr[str] = undefined.Undefined
 162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
 163            raw_name
 164        ):
 165            name = raw_name
 166
 167        code: typing.Optional[int] = None
 168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
 169            code = int(raw_code)
 170
 171        bungie_id: typing.Optional[int] = None
 172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
 173            bungie_id = int(raw_bungie_id)
 174
 175        return user.SearchableDestinyUser(
 176            name=name,
 177            code=code,
 178            bungie_id=bungie_id,
 179            memberships=self.deserialize_destiny_memberships(
 180                payload["destinyMemberships"]
 181            ),
 182        )
 183
 184    def deserialize_user_credentials(
 185        self, payload: typedefs.JSONArray
 186    ) -> collections.Sequence[user.UserCredentials]:
 187        return [
 188            user.UserCredentials(
 189                type=enums.CredentialType(int(creds["credentialType"])),
 190                display_name=creds["credentialDisplayName"],
 191                is_public=creds["isPublic"],
 192                self_as_string=creds.get("credentialAsString", undefined.Undefined),
 193            )
 194            for creds in payload
 195        ]
 196
 197    @staticmethod
 198    def set_themese_attrs(
 199        payload: typedefs.JSONArray, /
 200    ) -> typing.Collection[user.UserThemes]:
 201        return [
 202            user.UserThemes(
 203                id=int(entry["userThemeId"]),
 204                name=entry["userThemeName"]
 205                if "userThemeName" in entry
 206                else undefined.Undefined,
 207                description=entry["userThemeDescription"]
 208                if "userThemeDescription" in entry
 209                else undefined.Undefined,
 210            )
 211            for entry in payload
 212        ]
 213
 214    def deserialize_user_themes(
 215        self, payload: typedefs.JSONArray
 216    ) -> collections.Sequence[user.UserThemes]:
 217        return list(self.set_themese_attrs(payload))
 218
 219    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
 220
 221        # This is kinda redundant
 222        data = payload
 223
 224        # This is always outside the details.
 225        current_user_map: typing.Optional[
 226            collections.Mapping[str, clans.ClanMember]
 227        ] = None
 228        if raw_current_user_map := payload.get("currentUserMemberMap"):
 229            current_user_map = {
 230                membership_type: self.deserialize_clan_member(membership)
 231                for membership_type, membership in raw_current_user_map.items()
 232            }
 233
 234        try:
 235            data = payload["detail"]
 236        except KeyError:
 237            pass
 238
 239        id = data["groupId"]
 240        name = data["name"]
 241        created_at = data["creationDate"]
 242        member_count = data["memberCount"]
 243        about = data["about"]
 244        motto = data["motto"]
 245        is_public = data["isPublic"]
 246        banner = assets.Image(str(data["bannerPath"]))
 247        avatar = assets.Image(str(data["avatarPath"]))
 248        tags = data["tags"]
 249        type = data["groupType"]
 250
 251        features = data["features"]
 252        features_obj = clans.ClanFeatures(
 253            max_members=features["maximumMembers"],
 254            max_membership_types=features["maximumMembershipsOfGroupType"],
 255            capabilities=features["capabilities"],
 256            membership_types=features["membershipTypes"],
 257            invite_permissions=features["invitePermissionOverride"],
 258            update_banner_permissions=features["updateBannerPermissionOverride"],
 259            update_culture_permissions=features["updateCulturePermissionOverride"],
 260            join_level=features["joinLevel"],
 261        )
 262
 263        information: typedefs.JSONObject = data["clanInfo"]
 264        progression: collections.Mapping[int, progressions.Progression] = {
 265            int(prog_hash): self.deserialize_progressions(prog)
 266            for prog_hash, prog in information["d2ClanProgressions"].items()
 267        }
 268
 269        founder: typedefs.NoneOr[clans.ClanMember] = None
 270        if raw_founder := payload.get("founder"):
 271            founder = self.deserialize_clan_member(raw_founder)
 272
 273        return clans.Clan(
 274            net=self._net,
 275            id=int(id),
 276            name=name,
 277            type=enums.GroupType(type),
 278            created_at=time.clean_date(created_at),
 279            member_count=member_count,
 280            motto=motto,
 281            about=about,
 282            is_public=is_public,
 283            banner=banner,
 284            avatar=avatar,
 285            tags=tags,
 286            features=features_obj,
 287            owner=founder,
 288            progressions=progression,
 289            call_sign=information["clanCallsign"],
 290            banner_data=information["clanBannerData"],
 291            chat_security=data["chatSecurity"],
 292            conversation_id=int(data["conversationId"]),
 293            allow_chat=data["allowChat"],
 294            theme=data["theme"],
 295            current_user_membership=current_user_map,
 296        )
 297
 298    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
 299        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
 300        return clans.ClanMember(
 301            net=self._net,
 302            last_seen_name=destiny_user.last_seen_name,
 303            id=destiny_user.id,
 304            name=destiny_user.name,
 305            icon=destiny_user.icon,
 306            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
 307            group_id=int(data["groupId"]),
 308            joined_at=time.clean_date(data["joinDate"]),
 309            types=destiny_user.types,
 310            is_public=destiny_user.is_public,
 311            type=destiny_user.type,
 312            code=destiny_user.code,
 313            is_online=data["isOnline"],
 314            crossave_override=destiny_user.crossave_override,
 315            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
 316            if "bungieNetUserInfo" in data
 317            else None,
 318            member_type=enums.ClanMemberType(int(data["memberType"])),
 319        )
 320
 321    def deserialize_clan_members(
 322        self, data: typedefs.JSONObject, /
 323    ) -> iterators.FlatIterator[clans.ClanMember]:
 324        return iterators.FlatIterator(
 325            [self.deserialize_clan_member(member) for member in data["results"]]
 326        )
 327
 328    def deserialize_group_member(
 329        self, payload: typedefs.JSONObject
 330    ) -> clans.GroupMember:
 331        member = payload["member"]
 332        return clans.GroupMember(
 333            net=self._net,
 334            join_date=time.clean_date(member["joinDate"]),
 335            group_id=int(member["groupId"]),
 336            member_type=enums.ClanMemberType(member["memberType"]),
 337            is_online=member["isOnline"],
 338            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
 339            inactive_memberships=payload.get("areAllMembershipsInactive", None),
 340            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
 341            group=self.deserialize_clan(payload["group"]),
 342        )
 343
 344    def _deserialize_clan_conversation(
 345        self, payload: typedefs.JSONObject
 346    ) -> clans.ClanConversation:
 347        return clans.ClanConversation(
 348            net=self._net,
 349            id=int(payload["conversationId"]),
 350            group_id=int(payload["groupId"]),
 351            name=(
 352                payload["chatName"]
 353                if not typedefs.is_unknown(payload["chatName"])
 354                else undefined.Undefined
 355            ),
 356            chat_enabled=payload["chatEnabled"],
 357            security=payload["chatSecurity"],
 358        )
 359
 360    def deserialize_clan_conversations(
 361        self, payload: typedefs.JSONArray
 362    ) -> collections.Sequence[clans.ClanConversation]:
 363        return [self._deserialize_clan_conversation(conv) for conv in payload]
 364
 365    def deserialize_app_owner(
 366        self, payload: typedefs.JSONObject
 367    ) -> application.ApplicationOwner:
 368        return application.ApplicationOwner(
 369            net=self._net,
 370            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
 371            id=int(payload["membershipId"]),
 372            type=enums.MembershipType(payload["membershipType"]),
 373            icon=assets.Image(str(payload["iconPath"])),
 374            is_public=payload["isPublic"],
 375            code=payload.get("bungieGlobalDisplayNameCode", None),
 376        )
 377
 378    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
 379        return application.Application(
 380            id=int(payload["applicationId"]),
 381            name=payload["name"],
 382            link=payload["link"],
 383            status=payload["status"],
 384            redirect_url=payload.get("redirectUrl", None),
 385            created_at=time.clean_date(str(payload["creationDate"])),
 386            published_at=time.clean_date(str(payload["firstPublished"])),
 387            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
 388            scope=payload.get("scope", undefined.Undefined),
 389        )
 390
 391    def _set_character_attrs(self, payload: typedefs.JSONObject) -> character.Character:
 392        total_time = time.format_played(int(payload["minutesPlayedTotal"]), suffix=True)
 393        return character.Character(
 394            net=self._net,
 395            id=int(payload["characterId"]),
 396            gender=enums.Gender(payload["genderType"]),
 397            race=enums.Race(payload["raceType"]),
 398            class_type=enums.Class(payload["classType"]),
 399            emblem=assets.Image(str(payload["emblemBackgroundPath"])),
 400            emblem_icon=assets.Image(str(payload["emblemPath"])),
 401            emblem_hash=int(payload["emblemHash"]),
 402            last_played=time.clean_date(payload["dateLastPlayed"]),
 403            total_played_time=total_time,
 404            member_id=int(payload["membershipId"]),
 405            member_type=enums.MembershipType(payload["membershipType"]),
 406            level=payload["baseCharacterLevel"],
 407            title_hash=payload.get("titleRecordHash", None),
 408            light=payload["light"],
 409            stats={enums.Stat(int(k)): v for k, v in payload["stats"].items()},
 410        )
 411
 412    def deserialize_profile(
 413        self, payload: typedefs.JSONObject, /
 414    ) -> typing.Optional[profile.Profile]:
 415        if (raw_profile := payload.get("data")) is None:
 416            return None
 417
 418        payload = raw_profile
 419        id = int(payload["userInfo"]["membershipId"])
 420        name = payload["userInfo"]["displayName"]
 421        is_public = payload["userInfo"]["isPublic"]
 422        type = enums.MembershipType(payload["userInfo"]["membershipType"])
 423        last_played = time.clean_date(str(payload["dateLastPlayed"]))
 424        character_ids = [int(cid) for cid in payload["characterIds"]]
 425        power_cap = payload["currentSeasonRewardPowerCap"]
 426
 427        return profile.Profile(
 428            id=int(id),
 429            name=name,
 430            is_public=is_public,
 431            type=type,
 432            last_played=last_played,
 433            character_ids=character_ids,
 434            power_cap=power_cap,
 435            net=self._net,
 436        )
 437
 438    def deserialize_profile_item(
 439        self, payload: typedefs.JSONObject
 440    ) -> profile.ProfileItemImpl:
 441
 442        instance_id: typing.Optional[int] = None
 443        if raw_instance_id := payload.get("itemInstanceId"):
 444            instance_id = int(raw_instance_id)
 445
 446        version_number: typing.Optional[int] = None
 447        if raw_version := payload.get("versionNumber"):
 448            version_number = int(raw_version)
 449
 450        transfer_status = enums.TransferStatus(payload["transferStatus"])
 451
 452        return profile.ProfileItemImpl(
 453            net=self._net,
 454            hash=payload["itemHash"],
 455            quantity=payload["quantity"],
 456            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
 457            location=enums.ItemLocation(payload["location"]),
 458            bucket=payload["bucketHash"],
 459            transfer_status=transfer_status,
 460            lockable=payload["lockable"],
 461            state=enums.ItemState(payload["state"]),
 462            dismantel_permissions=payload["dismantlePermission"],
 463            is_wrapper=payload["isWrapper"],
 464            instance_id=instance_id,
 465            version_number=version_number,
 466            ornament_id=payload.get("overrideStyleItemHash"),
 467        )
 468
 469    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
 470        return records.Objective(
 471            net=self._net,
 472            hash=payload["objectiveHash"],
 473            visible=payload["visible"],
 474            complete=payload["complete"],
 475            completion_value=payload["completionValue"],
 476            progress=payload.get("progress"),
 477            destination_hash=payload.get("destinationHash"),
 478            activity_hash=payload.get("activityHash"),
 479        )
 480
 481    def deserialize_records(
 482        self,
 483        payload: typedefs.JSONObject,
 484        scores: typing.Optional[records.RecordScores] = None,
 485        **nodes: int,
 486    ) -> records.Record:
 487        objectives: typing.Optional[list[records.Objective]] = None
 488        interval_objectives: typing.Optional[list[records.Objective]] = None
 489        record_state: typedefs.IntAnd[records.RecordState]
 490
 491        record_state = records.RecordState(payload["state"])
 492
 493        if raw_objs := payload.get("objectives"):
 494            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
 495
 496        if raw_interval_objs := payload.get("intervalObjectives"):
 497            interval_objectives = [
 498                self.deserialize_objectives(obj) for obj in raw_interval_objs
 499            ]
 500
 501        return records.Record(
 502            scores=scores,
 503            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
 504            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
 505            state=record_state,
 506            objectives=objectives,
 507            interval_objectives=interval_objectives,
 508            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 509            completion_times=payload.get("completedCount", None),
 510            reward_visibility=payload.get("rewardVisibilty", None),
 511        )
 512
 513    def deserialize_character_records(
 514        self,
 515        payload: typedefs.JSONObject,
 516        scores: typing.Optional[records.RecordScores] = None,
 517        record_hashes: typing.Optional[list[int]] = None,
 518    ) -> records.CharacterRecord:
 519
 520        record = self.deserialize_records(payload, scores)
 521        return records.CharacterRecord(
 522            scores=scores,
 523            categories_node_hash=record.categories_node_hash,
 524            seals_node_hash=record.seals_node_hash,
 525            state=record.state,
 526            objectives=record.objectives,
 527            interval_objectives=record.interval_objectives,
 528            redeemed_count=payload.get("intervalsRedeemedCount", 0),
 529            completion_times=payload.get("completedCount"),
 530            reward_visibility=payload.get("rewardVisibilty"),
 531            record_hashes=record_hashes or [],
 532        )
 533
 534    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
 535        return character.Dye(
 536            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
 537        )
 538
 539    def deserialize_character_customization(
 540        self, payload: typedefs.JSONObject
 541    ) -> character.CustomizationOptions:
 542        return character.CustomizationOptions(
 543            personality=payload["personality"],
 544            face=payload["face"],
 545            skin_color=payload["skinColor"],
 546            lip_color=payload["lipColor"],
 547            eye_color=payload["eyeColor"],
 548            hair_colors=payload.get("hairColors", []),
 549            feature_colors=payload.get("featureColors", []),
 550            decal_color=payload["decalColor"],
 551            wear_helmet=payload["wearHelmet"],
 552            hair_index=payload["hairIndex"],
 553            feature_index=payload["featureIndex"],
 554            decal_index=payload["decalIndex"],
 555        )
 556
 557    def deserialize_character_minimal_equipments(
 558        self, payload: typedefs.JSONObject
 559    ) -> character.MinimalEquipments:
 560        dyes = None
 561        if raw_dyes := payload.get("dyes"):
 562            if raw_dyes:
 563                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
 564        return character.MinimalEquipments(
 565            net=self._net, item_hash=payload["itemHash"], dyes=dyes
 566        )
 567
 568    def deserialize_character_render_data(
 569        self, payload: typedefs.JSONObject, /
 570    ) -> character.RenderedData:
 571        return character.RenderedData(
 572            net=self._net,
 573            customization=self.deserialize_character_customization(
 574                payload["customization"]
 575            ),
 576            custom_dyes=[
 577                self.deserialize_character_dye(dye)
 578                for dye in payload["customDyes"]
 579                if dye
 580            ],
 581            equipment=[
 582                self.deserialize_character_minimal_equipments(equipment)
 583                for equipment in payload["peerView"]["equipment"]
 584            ],
 585        )
 586
 587    def deserialize_available_activity(
 588        self, payload: typedefs.JSONObject
 589    ) -> activity.AvailableActivity:
 590        return activity.AvailableActivity(
 591            hash=payload["activityHash"],
 592            is_new=payload["isNew"],
 593            is_completed=payload["isCompleted"],
 594            is_visible=payload["isVisible"],
 595            display_level=payload.get("displayLevel"),
 596            recommended_light=payload.get("recommendedLight"),
 597            difficulty=activity.Difficulty(payload["difficultyTier"]),
 598            can_join=payload["canJoin"],
 599            can_lead=payload["canLead"],
 600        )
 601
 602    def deserialize_character_activity(
 603        self, payload: typedefs.JSONObject
 604    ) -> activity.CharacterActivity:
 605        current_mode: typing.Optional[enums.GameMode] = None
 606        if raw_current_mode := payload.get("currentActivityModeType"):
 607            current_mode = enums.GameMode(raw_current_mode)
 608
 609        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
 610        if raw_current_modes := payload.get("currentActivityModeTypes"):
 611            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
 612
 613        return activity.CharacterActivity(
 614            date_started=time.clean_date(payload["dateActivityStarted"]),
 615            current_hash=payload["currentActivityHash"],
 616            current_mode_hash=payload["currentActivityModeHash"],
 617            current_mode=current_mode,
 618            current_mode_hashes=payload.get("currentActivityModeHashes"),
 619            current_mode_types=current_mode_types,
 620            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
 621            last_story_hash=payload["lastCompletedStoryHash"],
 622            available_activities=[
 623                self.deserialize_available_activity(activity_)
 624                for activity_ in payload["availableActivities"]
 625            ],
 626        )
 627
 628    def deserialize_profile_items(
 629        self, payload: typedefs.JSONObject, /
 630    ) -> list[profile.ProfileItemImpl]:
 631        return [self.deserialize_profile_item(item) for item in payload["items"]]
 632
 633    def _deserialize_node(self, payload: typedefs.JSONObject) -> records.Node:
 634        return records.Node(
 635            state=int(payload["state"]),
 636            objective=self.deserialize_objectives(payload["objective"])
 637            if "objective" in payload
 638            else None,
 639            progress_value=int(payload["progressValue"]),
 640            completion_value=int(payload["completionValue"]),
 641            record_category_score=int(payload["recordCategoryScore"])
 642            if "recordCategoryScore" in payload
 643            else None,
 644        )
 645
 646    @staticmethod
 647    def _deserialize_collectible(payload: typedefs.JSONObject) -> items.Collectible:
 648        recent_collectibles: typing.Optional[collections.Collection[int]] = None
 649        if raw_recent_collectibles := payload.get("recentCollectibleHashes"):
 650            recent_collectibles = [
 651                int(item_hash) for item_hash in raw_recent_collectibles
 652            ]
 653
 654        collectibles: dict[int, int] = {}
 655        for item_hash, mapping in payload["collectibles"].items():
 656            collectibles[int(item_hash)] = int(mapping["state"])
 657
 658        return items.Collectible(
 659            recent_collectibles=recent_collectibles,
 660            collectibles=collectibles,
 661            collection_categorie_hash=int(payload["collectionCategoriesRootNodeHash"]),
 662            collection_badges_hash=int(payload["collectionBadgesRootNodeHash"]),
 663        )
 664
 665    @staticmethod
 666    def _deserialize_currencies(
 667        payload: typedefs.JSONObject,
 668    ) -> collections.Sequence[items.Currency]:
 669        return [
 670            items.Currency(hash=int(item_hash), amount=int(amount))
 671            for item_hash, amount in payload["itemQuantities"].items()
 672        ]
 673
 674    def deserialize_progressions(
 675        self, payload: typedefs.JSONObject
 676    ) -> progressions.Progression:
 677        return progressions.Progression(
 678            hash=int(payload["progressionHash"]),
 679            level=int(payload["level"]),
 680            cap=int(payload["levelCap"]),
 681            daily_limit=int(payload["dailyLimit"]),
 682            weekly_limit=int(payload["weeklyLimit"]),
 683            current_progress=int(payload["currentProgress"]),
 684            daily_progress=int(payload["dailyProgress"]),
 685            needed=int(payload["progressToNextLevel"]),
 686            next_level=int(payload["nextLevelAt"]),
 687        )
 688
 689    def _deserialize_factions(
 690        self, payload: typedefs.JSONObject
 691    ) -> progressions.Factions:
 692        progs = self.deserialize_progressions(payload)
 693        return progressions.Factions(
 694            hash=progs.hash,
 695            level=progs.level,
 696            cap=progs.cap,
 697            daily_limit=progs.daily_limit,
 698            weekly_limit=progs.weekly_limit,
 699            current_progress=progs.current_progress,
 700            daily_progress=progs.daily_progress,
 701            needed=progs.needed,
 702            next_level=progs.next_level,
 703            faction_hash=payload["factionHash"],
 704            faction_vendor_hash=payload["factionVendorIndex"],
 705        )
 706
 707    def _deserialize_milestone_available_quest(
 708        self, payload: typedefs.JSONObject
 709    ) -> milestones.MilestoneQuest:
 710        return milestones.MilestoneQuest(
 711            item_hash=payload["questItemHash"],
 712            status=self._deserialize_milestone_quest_status(payload["status"]),
 713        )
 714
 715    def _deserialize_milestone_activity(
 716        self, payload: typedefs.JSONObject
 717    ) -> milestones.MilestoneActivity:
 718
 719        phases: typing.Optional[
 720            collections.Sequence[milestones.MilestoneActivityPhase]
 721        ] = None
 722        if raw_phases := payload.get("phases"):
 723            phases = [
 724                milestones.MilestoneActivityPhase(
 725                    is_completed=obj["complete"], hash=obj["phaseHash"]
 726                )
 727                for obj in raw_phases
 728            ]
 729
 730        return milestones.MilestoneActivity(
 731            hash=payload["activityHash"],
 732            challenges=[
 733                self.deserialize_objectives(obj["objective"])
 734                for obj in payload["challenges"]
 735            ],
 736            modifier_hashes=payload.get("modifierHashes"),
 737            boolean_options=payload.get("booleanActivityOptions"),
 738            phases=phases,
 739        )
 740
 741    def _deserialize_milestone_quest_status(
 742        self, payload: typedefs.JSONObject
 743    ) -> milestones.QuestStatus:
 744        return milestones.QuestStatus(
 745            net=self._net,
 746            quest_hash=payload["questHash"],
 747            step_hash=payload["stepHash"],
 748            step_objectives=[
 749                self.deserialize_objectives(objective)
 750                for objective in payload["stepObjectives"]
 751            ],
 752            is_tracked=payload["tracked"],
 753            is_completed=payload["completed"],
 754            started=payload["started"],
 755            item_instance_id=payload["itemInstanceId"],
 756            vendor_hash=payload.get("vendorHash"),
 757            is_redeemed=payload["redeemed"],
 758        )
 759
 760    def _deserialize_milestone_rewards(
 761        self, payload: typedefs.JSONObject
 762    ) -> milestones.MilestoneReward:
 763        return milestones.MilestoneReward(
 764            category_hash=payload["rewardCategoryHash"],
 765            entries=[
 766                milestones.MilestoneRewardEntry(
 767                    entry_hash=entry["rewardEntryHash"],
 768                    is_earned=entry["earned"],
 769                    is_redeemed=entry["redeemed"],
 770                )
 771                for entry in payload["entries"]
 772            ],
 773        )
 774
 775    def deserialize_milestone(
 776        self, payload: typedefs.JSONObject
 777    ) -> milestones.Milestone:
 778        start_date: typing.Optional[datetime.datetime] = None
 779        if raw_start_date := payload.get("startDate"):
 780            start_date = time.clean_date(raw_start_date)
 781
 782        end_date: typing.Optional[datetime.datetime] = None
 783        if raw_end_date := payload.get("endDate"):
 784            end_date = time.clean_date(raw_end_date)
 785
 786        rewards: typing.Optional[
 787            collections.Collection[milestones.MilestoneReward]
 788        ] = None
 789        if raw_rewards := payload.get("rewards"):
 790            rewards = [
 791                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
 792            ]
 793
 794        activities: typing.Optional[
 795            collections.Sequence[milestones.MilestoneActivity]
 796        ] = None
 797        if raw_activities := payload.get("activities"):
 798            activities = [
 799                self._deserialize_milestone_activity(active)
 800                for active in raw_activities
 801            ]
 802
 803        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
 804        if raw_quests := payload.get("availableQuests"):
 805            quests = [
 806                self._deserialize_milestone_available_quest(quest)
 807                for quest in raw_quests
 808            ]
 809
 810        vendors: typing.Optional[
 811            collections.Sequence[milestones.MilestoneVendor]
 812        ] = None
 813        if raw_vendors := payload.get("vendors"):
 814            vendors = [
 815                milestones.MilestoneVendor(
 816                    vendor_hash=vendor["vendorHash"],
 817                    preview_itemhash=vendor.get("previewItemHash"),
 818                )
 819                for vendor in raw_vendors
 820            ]
 821
 822        return milestones.Milestone(
 823            hash=payload["milestoneHash"],
 824            start_date=start_date,
 825            end_date=end_date,
 826            order=payload["order"],
 827            rewards=rewards,
 828            available_quests=quests,
 829            activities=activities,
 830            vendors=vendors,
 831        )
 832
 833    def _deserialize_artifact_tiers(
 834        self, payload: typedefs.JSONObject
 835    ) -> season.ArtifactTier:
 836        return season.ArtifactTier(
 837            hash=payload["tierHash"],
 838            is_unlocked=payload["isUnlocked"],
 839            points_to_unlock=payload["pointsToUnlock"],
 840            items=[
 841                season.ArtifactTierItem(
 842                    hash=item["itemHash"], is_active=item["isActive"]
 843                )
 844                for item in payload["items"]
 845            ],
 846        )
 847
 848    def deserialize_characters(
 849        self, payload: typedefs.JSONObject
 850    ) -> collections.Mapping[int, character.Character]:
 851        return {
 852            int(char_id): self._set_character_attrs(char)
 853            for char_id, char in payload["data"].items()
 854        }
 855
 856    def deserialize_character(
 857        self, payload: typedefs.JSONObject
 858    ) -> character.Character:
 859        return self._set_character_attrs(payload)
 860
 861    def deserialize_character_equipments(
 862        self, payload: typedefs.JSONObject
 863    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
 864        return {
 865            int(char_id): self.deserialize_profile_items(item)
 866            for char_id, item in payload["data"].items()
 867        }
 868
 869    def deserialize_character_activities(
 870        self, payload: typedefs.JSONObject
 871    ) -> collections.Mapping[int, activity.CharacterActivity]:
 872        return {
 873            int(char_id): self.deserialize_character_activity(data)
 874            for char_id, data in payload["data"].items()
 875        }
 876
 877    def deserialize_characters_render_data(
 878        self, payload: typedefs.JSONObject
 879    ) -> collections.Mapping[int, character.RenderedData]:
 880        return {
 881            int(char_id): self.deserialize_character_render_data(data)
 882            for char_id, data in payload["data"].items()
 883        }
 884
 885    def deserialize_character_progressions(
 886        self, payload: typedefs.JSONObject
 887    ) -> character.CharacterProgression:
 888        progressions_ = {
 889            int(prog_id): self.deserialize_progressions(prog)
 890            for prog_id, prog in payload["progressions"].items()
 891        }
 892
 893        factions = {
 894            int(faction_id): self._deserialize_factions(faction)
 895            for faction_id, faction in payload["factions"].items()
 896        }
 897
 898        milestones_ = {
 899            int(milestone_hash): self.deserialize_milestone(milestone)
 900            for milestone_hash, milestone in payload["milestones"].items()
 901        }
 902
 903        uninstanced_item_objectives = {
 904            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
 905            for item_hash, obj in payload["uninstancedItemObjectives"].items()
 906        }
 907
 908        artifact = payload["seasonalArtifact"]
 909        seasonal_artifact = season.CharacterScopedArtifact(
 910            hash=artifact["artifactHash"],
 911            points_used=artifact["pointsUsed"],
 912            reset_count=artifact["resetCount"],
 913            tiers=[
 914                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
 915            ],
 916        )
 917        checklists = payload["checklists"]
 918
 919        return character.CharacterProgression(
 920            progressions=progressions_,
 921            factions=factions,
 922            checklists=checklists,
 923            milestones=milestones_,
 924            seasonal_artifact=seasonal_artifact,
 925            uninstanced_item_objectives=uninstanced_item_objectives,
 926        )
 927
 928    def deserialize_character_progressions_mapping(
 929        self, payload: typedefs.JSONObject
 930    ) -> collections.Mapping[int, character.CharacterProgression]:
 931        character_progressions: collections.Mapping[
 932            int, character.CharacterProgression
 933        ] = {}
 934        for char_id, data in payload["data"].items():
 935            # A little hack to stop mypy complaining about Mapping <-> dict
 936            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
 937        return character_progressions
 938
 939    def deserialize_characters_records(
 940        self,
 941        payload: typedefs.JSONObject,
 942    ) -> collections.Mapping[int, records.CharacterRecord]:
 943
 944        return {
 945            int(rec_id): self.deserialize_character_records(
 946                rec, record_hashes=payload.get("featuredRecordHashes")
 947            )
 948            for rec_id, rec in payload["records"].items()
 949        }
 950
 951    def deserialize_profile_records(
 952        self, payload: typedefs.JSONObject
 953    ) -> collections.Mapping[int, records.Record]:
 954        raw_profile_records = payload["data"]
 955        scores = records.RecordScores(
 956            current_score=raw_profile_records["score"],
 957            legacy_score=raw_profile_records["legacyScore"],
 958            lifetime_score=raw_profile_records["lifetimeScore"],
 959        )
 960        return {
 961            int(record_id): self.deserialize_records(
 962                record,
 963                scores,
 964                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
 965                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
 966            )
 967            for record_id, record in raw_profile_records["records"].items()
 968        }
 969
 970    def _deserialize_craftable_socket_plug(
 971        self, payload: typedefs.JSONObject
 972    ) -> items.CraftableSocketPlug:
 973        return items.CraftableSocketPlug(
 974            item_hash=int(payload["plugItemHash"]),
 975            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 976        )
 977
 978    def _deserialize_craftable_socket(
 979        self, payload: typedefs.JSONObject
 980    ) -> items.CraftableSocket:
 981
 982        plugs: list[items.CraftableSocketPlug] = []
 983        if raw_plug := payload.get("plug"):
 984            plugs.extend(
 985                self._deserialize_craftable_socket_plug(plug) for plug in raw_plug
 986            )
 987
 988        return items.CraftableSocket(
 989            plug_set_hash=int(payload["plugSetHash"]), plugs=plugs
 990        )
 991
 992    def _deserialize_craftable_item(
 993        self, payload: typedefs.JSONObject
 994    ) -> items.CraftableItem:
 995
 996        return items.CraftableItem(
 997            is_visible=payload["visible"],
 998            failed_requirement_indexes=payload.get("failedRequirementIndexes", []),
 999            sockets=[
1000                self._deserialize_craftable_socket(socket)
1001                for socket in payload["sockets"]
1002            ],
1003        )
1004
1005    def deserialize_craftables_component(
1006        self, payload: typedefs.JSONObject
1007    ) -> components.CraftablesComponent:
1008        return components.CraftablesComponent(
1009            net=self._net,
1010            craftables={
1011                int(item_id): self._deserialize_craftable_item(item)
1012                for item_id, item in payload["craftables"].items()
1013                if item is not None
1014            },
1015            crafting_root_node_hash=payload["craftingRootNodeHash"],
1016        )
1017
1018    def deserialize_components(  # noqa: C901 Too complex.
1019        self, payload: typedefs.JSONObject
1020    ) -> components.Component:
1021
1022        profile_: typing.Optional[profile.Profile] = None
1023        if raw_profile := payload.get("profile"):
1024            profile_ = self.deserialize_profile(raw_profile)
1025
1026        profile_progression: typing.Optional[profile.ProfileProgression] = None
1027        if raw_profile_progression := payload.get("profileProgression"):
1028            profile_progression = self.deserialize_profile_progression(
1029                raw_profile_progression
1030            )
1031
1032        profile_currencies: typing.Optional[
1033            collections.Sequence[profile.ProfileItemImpl]
1034        ] = None
1035        if raw_profile_currencies := payload.get("profileCurrencies"):
1036            if "data" in raw_profile_currencies:
1037                profile_currencies = self.deserialize_profile_items(
1038                    raw_profile_currencies["data"]
1039                )
1040
1041        profile_inventories: typing.Optional[
1042            collections.Sequence[profile.ProfileItemImpl]
1043        ] = None
1044        if raw_profile_inventories := payload.get("profileInventory"):
1045            if "data" in raw_profile_inventories:
1046                profile_inventories = self.deserialize_profile_items(
1047                    raw_profile_inventories["data"]
1048                )
1049
1050        profile_records: typing.Optional[
1051            collections.Mapping[int, records.Record]
1052        ] = None
1053
1054        if raw_profile_records_ := payload.get("profileRecords"):
1055            profile_records = self.deserialize_profile_records(raw_profile_records_)
1056
1057        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1058        if raw_characters := payload.get("characters"):
1059            characters = self.deserialize_characters(raw_characters)
1060
1061        character_records: typing.Optional[
1062            collections.Mapping[int, records.CharacterRecord]
1063        ] = None
1064
1065        if raw_character_records := payload.get("characterRecords"):
1066            # Had to do it in two steps..
1067            to_update: typedefs.JSONObject = {}
1068            for _, data in raw_character_records["data"].items():
1069                for record_id, record in data.items():
1070                    to_update[record_id] = record
1071
1072            character_records = {
1073                int(rec_id): self.deserialize_character_records(
1074                    rec, record_hashes=to_update.get("featuredRecordHashes")
1075                )
1076                for rec_id, rec in to_update["records"].items()
1077            }
1078
1079        character_equipments: typing.Optional[
1080            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1081        ] = None
1082        if raw_character_equips := payload.get("characterEquipment"):
1083            character_equipments = self.deserialize_character_equipments(
1084                raw_character_equips
1085            )
1086
1087        character_inventories: typing.Optional[
1088            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1089        ] = None
1090        if raw_character_inventories := payload.get("characterInventories"):
1091            if "data" in raw_character_inventories:
1092                character_inventories = self.deserialize_character_equipments(
1093                    raw_character_inventories
1094                )
1095
1096        character_activities: typing.Optional[
1097            collections.Mapping[int, activity.CharacterActivity]
1098        ] = None
1099        if raw_char_acts := payload.get("characterActivities"):
1100            character_activities = self.deserialize_character_activities(raw_char_acts)
1101
1102        character_render_data: typing.Optional[
1103            collections.Mapping[int, character.RenderedData]
1104        ] = None
1105        if raw_character_render_data := payload.get("characterRenderData"):
1106            character_render_data = self.deserialize_characters_render_data(
1107                raw_character_render_data
1108            )
1109
1110        character_progressions: typing.Optional[
1111            collections.Mapping[int, character.CharacterProgression]
1112        ] = None
1113
1114        if raw_character_progressions := payload.get("characterProgressions"):
1115            character_progressions = self.deserialize_character_progressions_mapping(
1116                raw_character_progressions
1117            )
1118
1119        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1120        if raw_profile_string_vars := payload.get("profileStringVariables"):
1121            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1122
1123        character_string_vars: typing.Optional[
1124            collections.Mapping[int, collections.Mapping[int, int]]
1125        ] = None
1126        if raw_character_string_vars := payload.get("characterStringVariables"):
1127            character_string_vars = {
1128                int(char_id): data["integerValuesByHash"]
1129                for char_id, data in raw_character_string_vars["data"].items()
1130            }
1131
1132        metrics: typing.Optional[
1133            collections.Sequence[
1134                collections.Mapping[
1135                    int, tuple[bool, typing.Optional[records.Objective]]
1136                ]
1137            ]
1138        ] = None
1139        root_node_hash: typing.Optional[int] = None
1140
1141        if raw_metrics := payload.get("metrics"):
1142            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1143            metrics = [
1144                {
1145                    int(metrics_hash): (
1146                        data["invisible"],
1147                        self.deserialize_objectives(data["objectiveProgress"])
1148                        if "objectiveProgress" in data
1149                        else None,
1150                    )
1151                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1152                }
1153            ]
1154        transitory: typing.Optional[fireteams.FireteamParty] = None
1155        if raw_transitory := payload.get("profileTransitoryData"):
1156            if "data" in raw_transitory:
1157                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1158
1159        item_components: typing.Optional[components.ItemsComponent] = None
1160        if raw_item_components := payload.get("itemComponents"):
1161            item_components = self.deserialize_items_component(raw_item_components)
1162
1163        profile_plugsets: typing.Optional[
1164            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1165        ] = None
1166
1167        if raw_profile_plugs := payload.get("profilePlugSets"):
1168            profile_plugsets = {
1169                int(index): [self.deserialize_plug_item_state(state) for state in data]
1170                for index, data in raw_profile_plugs["data"]["plugs"].items()
1171            }
1172
1173        character_plugsets: typing.Optional[
1174            collections.Mapping[
1175                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1176            ]
1177        ] = None
1178        if raw_char_plugsets := payload.get("characterPlugSets"):
1179            character_plugsets = {
1180                int(char_id): {
1181                    int(index): [
1182                        self.deserialize_plug_item_state(state) for state in data
1183                    ]
1184                    for index, data in inner["plugs"].items()
1185                }
1186                for char_id, inner in raw_char_plugsets["data"].items()
1187            }
1188
1189        character_collectibles: typing.Optional[
1190            collections.Mapping[int, items.Collectible]
1191        ] = None
1192        if raw_character_collectibles := payload.get("characterCollectibles"):
1193            character_collectibles = {
1194                int(char_id): self._deserialize_collectible(data)
1195                for char_id, data in raw_character_collectibles["data"].items()
1196            }
1197
1198        profile_collectibles: typing.Optional[items.Collectible] = None
1199        if raw_profile_collectibles := payload.get("profileCollectibles"):
1200            profile_collectibles = self._deserialize_collectible(
1201                raw_profile_collectibles["data"]
1202            )
1203
1204        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1205        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1206            profile_nodes = {
1207                int(node_hash): self._deserialize_node(node)
1208                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1209            }
1210
1211        character_nodes: typing.Optional[
1212            collections.Mapping[int, collections.Mapping[int, records.Node]]
1213        ] = None
1214        if raw_character_nodes := payload.get("characterPresentationNodes"):
1215            character_nodes = {
1216                int(char_id): {
1217                    int(node_hash): self._deserialize_node(node)
1218                    for node_hash, node in each_character["nodes"].items()
1219                }
1220                for char_id, each_character in raw_character_nodes["data"].items()
1221            }
1222
1223        platform_silver: typing.Optional[
1224            collections.Mapping[str, profile.ProfileItemImpl]
1225        ] = None
1226        if raw_platform_silver := payload.get("platformSilver"):
1227            if "data" in raw_platform_silver:
1228                platform_silver = {
1229                    platform_name: self.deserialize_profile_item(item)
1230                    for platform_name, item in raw_platform_silver["data"][
1231                        "platformSilver"
1232                    ].items()
1233                }
1234
1235        character_currency_lookups: typing.Optional[
1236            collections.Mapping[int, collections.Sequence[items.Currency]]
1237        ] = None
1238        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1239            if "data" in raw_char_lookups:
1240                character_currency_lookups = {
1241                    int(char_id): self._deserialize_currencies(currencie)
1242                    for char_id, currencie in raw_char_lookups["data"].items()
1243                }
1244
1245        character_craftables: typing.Optional[
1246            collections.Mapping[int, components.CraftablesComponent]
1247        ] = None
1248        if raw_character_craftables := payload.get("characterCraftables"):
1249
1250            if "data" in raw_character_craftables:
1251                character_craftables = {
1252                    int(char_id): self.deserialize_craftables_component(craftable)
1253                    for char_id, craftable in raw_character_craftables["data"].items()
1254                }
1255
1256        return components.Component(
1257            profiles=profile_,
1258            profile_progression=profile_progression,
1259            profile_currencies=profile_currencies,
1260            profile_inventories=profile_inventories,
1261            profile_records=profile_records,
1262            characters=characters,
1263            character_records=character_records,
1264            character_equipments=character_equipments,
1265            character_inventories=character_inventories,
1266            character_activities=character_activities,
1267            character_render_data=character_render_data,
1268            character_progressions=character_progressions,
1269            profile_string_variables=profile_string_vars,
1270            character_string_variables=character_string_vars,
1271            metrics=metrics,
1272            root_node_hash=root_node_hash,
1273            transitory=transitory,
1274            item_components=item_components,
1275            profile_plugsets=profile_plugsets,
1276            character_plugsets=character_plugsets,
1277            character_collectibles=character_collectibles,
1278            profile_collectibles=profile_collectibles,
1279            profile_nodes=profile_nodes,
1280            character_nodes=character_nodes,
1281            platform_silver=platform_silver,
1282            character_currency_lookups=character_currency_lookups,
1283            character_craftables=character_craftables,
1284        )
1285
1286    def deserialize_items_component(
1287        self, payload: typedefs.JSONObject
1288    ) -> components.ItemsComponent:
1289        instances: typing.Optional[
1290            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1291        ] = None
1292        if raw_instances := payload.get("instances"):
1293            instances = [
1294                {
1295                    int(ins_id): self.deserialize_instanced_item(item)
1296                    for ins_id, item in raw_instances["data"].items()
1297                }
1298            ]
1299
1300        render_data: typing.Optional[
1301            collections.Mapping[int, tuple[bool, dict[int, int]]]
1302        ] = None
1303        if raw_render_data := payload.get("renderData"):
1304            render_data = {
1305                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1306                for ins_id, data in raw_render_data["data"].items()
1307            }
1308
1309        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1310        if raw_stats := payload.get("stats"):
1311            builder: collections.Mapping[int, items.ItemStatsView] = {}
1312            for ins_id, stat in raw_stats["data"].items():
1313                for _, items_ in stat.items():
1314                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1315            stats = builder
1316
1317        sockets: typing.Optional[
1318            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1319        ] = None
1320        if raw_sockets := payload.get("sockets"):
1321            sockets = {
1322                int(ins_id): [
1323                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1324                ]
1325                for ins_id, item in raw_sockets["data"].items()
1326            }
1327
1328        objeectives: typing.Optional[
1329            collections.Mapping[int, collections.Sequence[records.Objective]]
1330        ] = None
1331        if raw_objectives := payload.get("objectives"):
1332            objeectives = {
1333                int(ins_id): [self.deserialize_objectives(objective)]
1334                for ins_id, data in raw_objectives["data"].items()
1335                for objective in data["objectives"]
1336            }
1337
1338        perks: typing.Optional[
1339            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1340        ] = None
1341        if raw_perks := payload.get("perks"):
1342            perks = {
1343                int(ins_id): [
1344                    self.deserialize_item_perk(perk) for perk in item["perks"]
1345                ]
1346                for ins_id, item in raw_perks["data"].items()
1347            }
1348
1349        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1350        if raw_plug_states := payload.get("plugStates"):
1351            pending_states: list[items.PlugItemState] = []
1352            for _, plug in raw_plug_states["data"].items():
1353                pending_states.append(self.deserialize_plug_item_state(plug))
1354            plug_states = pending_states
1355
1356        reusable_plugs: typing.Optional[
1357            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1358        ] = None
1359        if raw_re_plugs := payload.get("reusablePlugs"):
1360            reusable_plugs = {
1361                int(ins_id): [
1362                    self.deserialize_plug_item_state(state) for state in inner
1363                ]
1364                for ins_id, plug in raw_re_plugs["data"].items()
1365                for inner in list(plug["plugs"].values())
1366            }
1367
1368        plug_objectives: typing.Optional[
1369            collections.Mapping[
1370                int, collections.Mapping[int, collections.Collection[records.Objective]]
1371            ]
1372        ] = None
1373        if raw_plug_objectives := payload.get("plugObjectives"):
1374            plug_objectives = {
1375                int(ins_id): {
1376                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1377                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1378                }
1379                for ins_id, inner in raw_plug_objectives["data"].items()
1380            }
1381
1382        return components.ItemsComponent(
1383            sockets=sockets,
1384            stats=stats,
1385            render_data=render_data,
1386            instances=instances,
1387            objectives=objeectives,
1388            perks=perks,
1389            plug_states=plug_states,
1390            reusable_plugs=reusable_plugs,
1391            plug_objectives=plug_objectives,
1392        )
1393
1394    def deserialize_character_component(  # type: ignore[call-arg]
1395        self, payload: typedefs.JSONObject
1396    ) -> components.CharacterComponent:
1397
1398        character_: typing.Optional[character.Character] = None
1399        if raw_singuler_character := payload.get("character"):
1400            character_ = self.deserialize_character(raw_singuler_character["data"])
1401
1402        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1403        if raw_inventory := payload.get("inventory"):
1404            if "data" in raw_inventory:
1405                inventory = self.deserialize_profile_items(raw_inventory["data"])
1406
1407        activities: typing.Optional[activity.CharacterActivity] = None
1408        if raw_activities := payload.get("activities"):
1409            activities = self.deserialize_character_activity(raw_activities["data"])
1410
1411        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1412        if raw_equipments := payload.get("equipment"):
1413            equipment = self.deserialize_profile_items(raw_equipments["data"])
1414
1415        progressions_: typing.Optional[character.CharacterProgression] = None
1416        if raw_progressions := payload.get("progressions"):
1417            progressions_ = self.deserialize_character_progressions(
1418                raw_progressions["data"]
1419            )
1420
1421        render_data: typing.Optional[character.RenderedData] = None
1422        if raw_render_data := payload.get("renderData"):
1423            render_data = self.deserialize_character_render_data(
1424                raw_render_data["data"]
1425            )
1426
1427        character_records: typing.Optional[
1428            collections.Mapping[int, records.CharacterRecord]
1429        ] = None
1430        if raw_char_records := payload.get("records"):
1431            character_records = self.deserialize_characters_records(
1432                raw_char_records["data"]
1433            )
1434
1435        item_components: typing.Optional[components.ItemsComponent] = None
1436        if raw_item_components := payload.get("itemComponents"):
1437            item_components = self.deserialize_items_component(raw_item_components)
1438
1439        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1440        if raw_nodes := payload.get("presentationNodes"):
1441            nodes = {
1442                int(node_hash): self._deserialize_node(node)
1443                for node_hash, node in raw_nodes["data"]["nodes"].items()
1444            }
1445
1446        collectibles: typing.Optional[items.Collectible] = None
1447        if raw_collectibles := payload.get("collectibles"):
1448            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1449
1450        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1451        if raw_currencies := payload.get("currencyLookups"):
1452            if "data" in raw_currencies:
1453                currency_lookups = self._deserialize_currencies(raw_currencies)
1454
1455        return components.CharacterComponent(
1456            activities=activities,
1457            equipment=equipment,
1458            inventory=inventory,
1459            progressions=progressions_,
1460            render_data=render_data,
1461            character=character_,
1462            character_records=character_records,
1463            profile_records=None,
1464            item_components=item_components,
1465            currency_lookups=currency_lookups,
1466            collectibles=collectibles,
1467            nodes=nodes,
1468        )
1469
1470    def _set_entity_attrs(
1471        self, payload: typedefs.JSONObject, *, key: str = "displayProperties"
1472    ) -> entity.Entity:
1473
1474        name: undefined.UndefinedOr[str] = undefined.Undefined
1475        description: undefined.UndefinedOr[str] = undefined.Undefined
1476
1477        if properties := payload[key]:
1478            if (raw_name := properties["name"]) is not typedefs.Unknown:
1479                name = raw_name
1480
1481            if (
1482                raw_description := properties["description"]
1483            ) and not typedefs.is_unknown(raw_description):
1484                description = raw_description
1485
1486        return entity.Entity(
1487            net=self._net,
1488            hash=payload["hash"],
1489            index=payload["index"],
1490            name=name,
1491            description=description,
1492            has_icon=properties["hasIcon"],
1493            icon=assets.Image(properties["icon"] if "icon" in properties else None),
1494        )
1495
1496    def deserialize_inventory_results(
1497        self, payload: typedefs.JSONObject
1498    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1499        suggested_words: list[str] = payload["suggestedWords"]
1500
1501        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1502            return s if not typedefs.is_unknown(s) else undefined.Undefined
1503
1504        return iterators.FlatIterator(
1505            [
1506                entity.SearchableEntity(
1507                    net=self._net,
1508                    hash=data["hash"],
1509                    entity_type=data["entityType"],
1510                    weight=data["weight"],
1511                    suggested_words=suggested_words,
1512                    name=data["displayProperties"]["name"],
1513                    has_icon=data["displayProperties"]["hasIcon"],
1514                    description=_check_unknown(
1515                        data["displayProperties"]["description"]
1516                    ),
1517                    icon=assets.Image(data["displayProperties"]["icon"]),
1518                )
1519                for data in payload["results"]["results"]
1520            ]
1521        )
1522
1523    def _deserialize_inventory_item_objects(
1524        self, payload: typedefs.JSONObject
1525    ) -> entity.InventoryEntityObjects:
1526        return entity.InventoryEntityObjects(
1527            action=payload.get("action"),
1528            set_data=payload.get("setData"),
1529            stats=payload.get("stats"),
1530            equipping_block=payload.get("equippingBlock"),
1531            translation_block=payload.get("translationBlock"),
1532            preview=payload.get("preview"),
1533            quality=payload.get("quality"),
1534            value=payload.get("value"),
1535            source_data=payload.get("sourceData"),
1536            objectives=payload.get("objectives"),
1537            plug=payload.get("plug"),
1538            metrics=payload.get("metrics"),
1539            gearset=payload.get("gearset"),
1540            sack=payload.get("sack"),
1541            sockets=payload.get("sockets"),
1542            summary=payload.get("summary"),
1543            talent_gird=payload.get("talentGrid"),
1544            investments_stats=payload.get("investmentStats"),
1545            perks=payload.get("perks"),
1546            animations=payload.get("animations", []),
1547            links=payload.get("links", []),
1548        )
1549
1550    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1551        self, payload: typedefs.JSONObject, /
1552    ) -> entity.InventoryEntity:
1553
1554        props = self._set_entity_attrs(payload)
1555        objects = self._deserialize_inventory_item_objects(payload)
1556
1557        collectible_hash: typing.Optional[int] = None
1558        if raw_collectible_hash := payload.get("collectibleHash"):
1559            collectible_hash = int(raw_collectible_hash)
1560
1561        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1562        if raw_second_icon := payload.get("secondaryIcon"):
1563            secondary_icon = assets.Image(raw_second_icon)
1564
1565        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1566        if raw_second_overlay := payload.get("secondaryOverlay"):
1567            secondary_overlay = assets.Image(raw_second_overlay)
1568
1569        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1570        if raw_second_special := payload.get("secondarySpecial"):
1571            secondary_special = assets.Image(raw_second_special)
1572
1573        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1574        if raw_screenshot := payload.get("screenshot"):
1575            screenshot = assets.Image(raw_screenshot)
1576
1577        watermark_icon: typing.Optional[assets.Image] = None
1578        if raw_watermark_icon := payload.get("iconWatermark"):
1579            watermark_icon = assets.Image(raw_watermark_icon)
1580
1581        watermark_shelved: typing.Optional[assets.Image] = None
1582        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1583            watermark_shelved = assets.Image(raw_watermark_shelved)
1584
1585        about: undefined.UndefinedOr[str] = undefined.Undefined
1586        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1587            raw_about
1588        ):
1589            about = raw_about
1590
1591        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1592        if (
1593            raw_ui_style := payload.get("uiItemDisplayStyle")
1594        ) and not typedefs.is_unknown(raw_ui_style):
1595            ui_item_style = raw_ui_style
1596
1597        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1598        if (
1599            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1600        ) and not typedefs.is_unknown(raw_tier_and_name):
1601            tier_and_name = raw_tier_and_name
1602
1603        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1604        if (
1605            raw_type_name := payload.get("itemTypeDisplayName")
1606        ) and not typedefs.is_unknown(raw_type_name):
1607            type_name = raw_type_name
1608
1609        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1610        if (
1611            raw_display_source := payload.get("displaySource")
1612        ) and not typedefs.is_unknown(raw_display_source):
1613            display_source = raw_display_source
1614
1615        lorehash: typing.Optional[int] = None
1616        if raw_lore_hash := payload.get("loreHash"):
1617            lorehash = int(raw_lore_hash)
1618
1619        summary_hash: typing.Optional[int] = None
1620        if raw_summary_hash := payload.get("summaryItemHash"):
1621            summary_hash = raw_summary_hash
1622
1623        breaker_type_hash: typing.Optional[int] = None
1624        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1625            breaker_type_hash = int(raw_breaker_type_hash)
1626
1627        damage_types: typing.Optional[collections.Sequence[int]] = None
1628        if raw_damage_types := payload.get("damageTypes"):
1629            damage_types = [int(type_) for type_ in raw_damage_types]
1630
1631        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1632        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1633            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1634
1635        default_damagetype_hash: typing.Optional[int] = None
1636        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1637            default_damagetype_hash = int(raw_defaultdmg_hash)
1638
1639        emblem_objective_hash: typing.Optional[int] = None
1640        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1641            emblem_objective_hash = int(raw_emblem_obj_hash)
1642
1643        tier_type: typing.Optional[enums.TierType] = None
1644        tier: typing.Optional[enums.ItemTier] = None
1645        bucket_hash: typing.Optional[int] = None
1646        recovery_hash: typing.Optional[int] = None
1647        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1648        isinstance_item: bool = False
1649        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1650        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1651        suppress_expiration: bool = False
1652        max_stack_size: typing.Optional[int] = None
1653        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1654
1655        if inventory := payload.get("inventory"):
1656            tier_type = enums.TierType(int(inventory["tierType"]))
1657            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1658            bucket_hash = int(inventory["bucketTypeHash"])
1659            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1660            tier_name = inventory["tierTypeName"]
1661            isinstance_item = inventory["isInstanceItem"]
1662            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1663            max_stack_size = int(inventory["maxStackSize"])
1664
1665            try:
1666                stack_label = inventory["stackUniqueLabel"]
1667            except KeyError:
1668                pass
1669
1670        return entity.InventoryEntity(
1671            net=self._net,
1672            collectible_hash=collectible_hash,
1673            name=props.name,
1674            about=about,
1675            emblem_objective_hash=emblem_objective_hash,
1676            suppress_expiration=suppress_expiration,
1677            max_stack_size=max_stack_size,
1678            stack_label=stack_label,
1679            tier=tier,
1680            tier_type=tier_type,
1681            tier_name=tier_name,
1682            bucket_hash=bucket_hash,
1683            recovery_bucket_hash=recovery_hash,
1684            isinstance_item=isinstance_item,
1685            expire_in_orbit_message=expire_in_orbit_message,
1686            expiration_tooltip=expire_tool_tip,
1687            lore_hash=lorehash,
1688            type_and_tier_name=tier_and_name,
1689            summary_hash=summary_hash,
1690            ui_display_style=ui_item_style,
1691            type_name=type_name,
1692            breaker_type_hash=breaker_type_hash,
1693            description=props.description,
1694            display_source=display_source,
1695            hash=props.hash,
1696            damage_types=damage_types,
1697            index=props.index,
1698            icon=props.icon,
1699            has_icon=props.has_icon,
1700            screenshot=screenshot,
1701            watermark_icon=watermark_icon,
1702            watermark_shelved=watermark_shelved,
1703            secondary_icon=secondary_icon,
1704            secondary_overlay=secondary_overlay,
1705            secondary_special=secondary_special,
1706            type=enums.ItemType(int(payload["itemType"])),
1707            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1708            trait_ids=[trait for trait in payload.get("traitIds", [])],
1709            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1710            item_class=enums.Class(int(payload["classType"])),
1711            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1712            breaker_type=int(payload["breakerType"]),
1713            default_damagetype=int(payload["defaultDamageType"]),
1714            default_damagetype_hash=default_damagetype_hash,
1715            damagetype_hashes=damagetype_hashes,
1716            tooltip_notifications=payload["tooltipNotifications"],
1717            not_transferable=payload["nonTransferrable"],
1718            allow_actions=payload["allowActions"],
1719            is_equippable=payload["equippable"],
1720            objects=objects,
1721            background_colors=payload.get("backgroundColor", {}),
1722            season_hash=payload.get("seasonHash"),
1723            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1724        )
1725
1726    def deserialize_objective_entity(
1727        self, payload: typedefs.JSONObject, /
1728    ) -> entity.ObjectiveEntity:
1729        props = self._set_entity_attrs(payload)
1730        return entity.ObjectiveEntity(
1731            net=self._net,
1732            hash=props.hash,
1733            index=props.index,
1734            description=props.description,
1735            name=props.name,
1736            has_icon=props.has_icon,
1737            icon=props.icon,
1738            unlock_value_hash=payload["unlockValueHash"],
1739            completion_value=payload["completionValue"],
1740            scope=entity.GatingScope(int(payload["scope"])),
1741            location_hash=payload["locationHash"],
1742            allowed_negative_value=payload["allowNegativeValue"],
1743            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1744            counting_downward=payload["isCountingDownward"],
1745            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1746            progress_description=payload["progressDescription"],
1747            perks=payload["perks"],
1748            stats=payload["stats"],
1749            minimum_visibility=payload["minimumVisibilityThreshold"],
1750            allow_over_completion=payload["allowOvercompletion"],
1751            show_value_style=payload["showValueOnComplete"],
1752            display_only_objective=payload["isDisplayOnlyObjective"],
1753            complete_value_style=entity.ValueUIStyle(
1754                int(payload["completedValueStyle"])
1755            ),
1756            progress_value_style=entity.ValueUIStyle(
1757                int(payload["inProgressValueStyle"])
1758            ),
1759            ui_label=payload["uiLabel"],
1760            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1761        )
1762
1763    def _deserialize_activity_values(
1764        self, payload: typedefs.JSONObject, /
1765    ) -> activity.ActivityValues:
1766        team: typing.Optional[int] = None
1767        if raw_team := payload.get("team"):
1768            team = raw_team["basic"]["value"]
1769        return activity.ActivityValues(
1770            assists=payload["assists"]["basic"]["value"],
1771            deaths=payload["deaths"]["basic"]["value"],
1772            kills=payload["kills"]["basic"]["value"],
1773            is_completed=bool(payload["completed"]["basic"]["value"]),
1774            opponents_defeated=payload["opponentsDefeated"]["basic"]["value"],
1775            efficiency=payload["efficiency"]["basic"]["value"],
1776            kd_ratio=payload["killsDeathsRatio"]["basic"]["value"],
1777            kd_assists=payload["killsDeathsAssists"]["basic"]["value"],
1778            score=payload["score"]["basic"]["value"],
1779            duration=payload["activityDurationSeconds"]["basic"]["displayValue"],
1780            team=team,
1781            completion_reason=payload["completionReason"]["basic"]["displayValue"],
1782            fireteam_id=payload["fireteamId"]["basic"]["value"],
1783            start_seconds=payload["startSeconds"]["basic"]["value"],
1784            played_time=payload["timePlayedSeconds"]["basic"]["displayValue"],
1785            player_count=payload["playerCount"]["basic"]["value"],
1786            team_score=payload["teamScore"]["basic"]["value"],
1787        )
1788
1789    def deserialize_activity(
1790        self,
1791        payload: typedefs.JSONObject,
1792        /,
1793    ) -> activity.Activity:
1794        period = time.clean_date(payload["period"])
1795        details = payload["activityDetails"]
1796        ref_id = int(details["referenceId"])
1797        instance_id = int(details["instanceId"])
1798        mode = enums.GameMode(details["mode"])
1799        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1800        is_private = details["isPrivate"]
1801        membership_type = enums.MembershipType(int(details["membershipType"]))
1802
1803        # Since we're using the same fields for post activity method
1804        # this check is required since post activity doesn't values values
1805        values = self._deserialize_activity_values(payload["values"])
1806
1807        return activity.Activity(
1808            net=self._net,
1809            hash=ref_id,
1810            instance_id=instance_id,
1811            mode=mode,
1812            modes=modes,
1813            is_private=is_private,
1814            membership_type=membership_type,
1815            occurred_at=period,
1816            values=values,
1817        )
1818
1819    def deserialize_activities(
1820        self, payload: typedefs.JSONObject
1821    ) -> iterators.FlatIterator[activity.Activity]:
1822        return iterators.FlatIterator(
1823            [
1824                self.deserialize_activity(activity_)
1825                for activity_ in payload["activities"]
1826            ]
1827        )
1828
1829    def deserialize_extended_weapon_values(
1830        self, payload: typedefs.JSONObject
1831    ) -> activity.ExtendedWeaponValues:
1832
1833        assists: typing.Optional[int] = None
1834        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1835            assists = raw_assists["basic"]["value"]
1836        assists_damage: typing.Optional[int] = None
1837
1838        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1839            assists_damage = raw_assists_damage["basic"]["value"]
1840
1841        return activity.ExtendedWeaponValues(
1842            reference_id=int(payload["referenceId"]),
1843            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1844            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1845                "value"
1846            ],
1847            assists=assists,
1848            assists_damage=assists_damage,
1849            precision_kills_percentage=(
1850                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1852                    "displayValue"
1853                ],
1854            ),
1855        )
1856
1857    def _deserialize_extended_values(
1858        self, payload: typedefs.JSONObject
1859    ) -> activity.ExtendedValues:
1860        weapons: typing.Optional[
1861            collections.Collection[activity.ExtendedWeaponValues]
1862        ] = None
1863
1864        if raw_weapons := payload.get("weapons"):
1865            weapons = [
1866                self.deserialize_extended_weapon_values(value) for value in raw_weapons
1867            ]
1868
1869        return activity.ExtendedValues(
1870            precision_kills=payload["values"]["precisionKills"]["basic"]["value"],
1871            grenade_kills=payload["values"]["weaponKillsGrenade"]["basic"]["value"],
1872            melee_kills=payload["values"]["weaponKillsMelee"]["basic"]["value"],
1873            super_kills=payload["values"]["weaponKillsSuper"]["basic"]["value"],
1874            ability_kills=payload["values"]["weaponKillsAbility"]["basic"]["value"],
1875            weapons=weapons,
1876        )
1877
1878    def deserialize_post_activity_player(
1879        self, payload: typedefs.JSONObject, /
1880    ) -> activity.PostActivityPlayer:
1881        player = payload["player"]
1882
1883        class_hash: typedefs.NoneOr[int] = None
1884        if (class_hash := player.get("classHash")) is not None:
1885            class_hash = class_hash
1886
1887        race_hash: typedefs.NoneOr[int] = None
1888        if (race_hash := player.get("raceHash")) is not None:
1889            race_hash = race_hash
1890
1891        gender_hash: typedefs.NoneOr[int] = None
1892        if (gender_hash := player.get("genderHash")) is not None:
1893            gender_hash = gender_hash
1894
1895        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1896        if (
1897            character_class := player.get("characterClass")
1898        ) and not typedefs.is_unknown(character_class):
1899            character_class = character_class
1900
1901        character_level: typedefs.NoneOr[int] = None
1902        if (character_level := player.get("characterLevel")) is not None:
1903            character_level = character_level
1904
1905        return activity.PostActivityPlayer(
1906            standing=int(payload["standing"]),
1907            score=int(payload["score"]["basic"]["value"]),
1908            character_id=payload["characterId"],
1909            destiny_user=self.deserialize_destiny_membership(
1910                player["destinyUserInfo"]
1911            ),
1912            character_class=character_class,
1913            character_level=character_level,
1914            race_hash=race_hash,
1915            gender_hash=gender_hash,
1916            class_hash=class_hash,
1917            light_level=int(player["lightLevel"]),
1918            emblem_hash=int(player["emblemHash"]),
1919            values=self._deserialize_activity_values(payload["values"]),
1920            extended_values=self._deserialize_extended_values(payload["extended"]),
1921        )
1922
1923    def _deserialize_post_activity_team(
1924        self, payload: typedefs.JSONObject
1925    ) -> activity.PostActivityTeam:
1926        return activity.PostActivityTeam(
1927            id=payload["teamId"],
1928            is_defeated=bool(payload["standing"]["basic"]["value"]),
1929            score=int(payload["score"]["basic"]["value"]),
1930            name=payload["teamName"],
1931        )
1932
1933    def deserialize_post_activity(
1934        self, payload: typedefs.JSONObject
1935    ) -> activity.PostActivity:
1936        period = time.clean_date(payload["period"])
1937        details = payload["activityDetails"]
1938        ref_id = int(details["referenceId"])
1939        instance_id = int(details["instanceId"])
1940        mode = enums.GameMode(details["mode"])
1941        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1942        is_private = details["isPrivate"]
1943        membership_type = enums.MembershipType(int(details["membershipType"]))
1944        return activity.PostActivity(
1945            net=self._net,
1946            hash=ref_id,
1947            membership_type=membership_type,
1948            instance_id=instance_id,
1949            mode=mode,
1950            modes=modes,
1951            is_private=is_private,
1952            occurred_at=period,
1953            starting_phase=int(payload["startingPhaseIndex"]),
1954            players=[
1955                self.deserialize_post_activity_player(player)
1956                for player in payload["entries"]
1957            ],
1958            teams=[
1959                self._deserialize_post_activity_team(team) for team in payload["teams"]
1960            ],
1961        )
1962
1963    def _deserialize_aggregated_activity_values(
1964        self, payload: typedefs.JSONObject
1965    ) -> activity.AggregatedActivityValues:
1966        # This ID is always the same for all aggregated values.
1967        activity_id = int(payload["fastestCompletionMsForActivity"]["activityId"])
1968
1969        return activity.AggregatedActivityValues(
1970            id=activity_id,
1971            fastest_completion_time=(
1972                int(payload["fastestCompletionMsForActivity"]["basic"]["value"]),
1973                payload["fastestCompletionMsForActivity"]["basic"]["displayValue"],
1974            ),
1975            completions=int(payload["activityCompletions"]["basic"]["value"]),
1976            kills=int(payload["activityKills"]["basic"]["value"]),
1977            deaths=int(payload["activityDeaths"]["basic"]["value"]),
1978            assists=int(payload["activityAssists"]["basic"]["value"]),
1979            seconds_played=(
1980                int(payload["activitySecondsPlayed"]["basic"]["value"]),
1981                payload["activitySecondsPlayed"]["basic"]["displayValue"],
1982            ),
1983            wins=int(payload["activityWins"]["basic"]["value"]),
1984            goals_missed=int(payload["activityGoalsMissed"]["basic"]["value"]),
1985            special_actions=int(payload["activitySpecialActions"]["basic"]["value"]),
1986            best_goals_hit=int(payload["activityBestGoalsHit"]["basic"]["value"]),
1987            best_single_score=int(
1988                payload["activityBestSingleGameScore"]["basic"]["value"]
1989            ),
1990            goals_hit=int(payload["activityGoalsHit"]["basic"]["value"]),
1991            special_score=int(payload["activitySpecialScore"]["basic"]["value"]),
1992            kd_assists=int(payload["activityKillsDeathsAssists"]["basic"]["value"]),
1993            kd_ratio=float(
1994                payload["activityKillsDeathsAssists"]["basic"]["displayValue"]
1995            ),
1996            precision_kills=int(payload["activityPrecisionKills"]["basic"]["value"]),
1997        )
1998
1999    def deserialize_aggregated_activity(
2000        self, payload: typedefs.JSONObject
2001    ) -> activity.AggregatedActivity:
2002        return activity.AggregatedActivity(
2003            hash=int(payload["activityHash"]),
2004            values=self._deserialize_aggregated_activity_values(payload["values"]),
2005        )
2006
2007    def deserialize_aggregated_activities(
2008        self, payload: typedefs.JSONObject
2009    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2010        return iterators.FlatIterator(
2011            [
2012                self.deserialize_aggregated_activity(activity)
2013                for activity in payload["activities"]
2014            ]
2015        )
2016
2017    def deserialize_linked_profiles(
2018        self, payload: typedefs.JSONObject
2019    ) -> profile.LinkedProfile:
2020        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2021        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2022        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2023
2024        if raw_profile := payload.get("profiles"):
2025            for pfile in raw_profile:
2026                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2027
2028        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2029            for raw_error_pfile in raw_profiles_with_errors:
2030                if error_pfile := raw_error_pfile.get("infoCard"):
2031                    error_profiles_vec.append(
2032                        self.deserialize_destiny_membership(error_pfile)
2033                    )
2034
2035        return profile.LinkedProfile(
2036            net=self._net,
2037            bungie=bungie_user,
2038            profiles=profiles_vec,
2039            profiles_with_errors=error_profiles_vec,
2040        )
2041
2042    def deserialize_clan_banners(
2043        self, payload: typedefs.JSONObject
2044    ) -> collections.Sequence[clans.ClanBanner]:
2045        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2046        if banners := payload.get("clanBannerDecals"):
2047            for k, v in banners.items():
2048                banner_obj = clans.ClanBanner(
2049                    id=int(k),
2050                    foreground=assets.Image(v["foregroundPath"]),
2051                    background=assets.Image(v["backgroundPath"]),
2052                )
2053                banners_seq.append(banner_obj)
2054        return banners_seq
2055
2056    def deserialize_public_milestone_content(
2057        self, payload: typedefs.JSONObject
2058    ) -> milestones.MilestoneContent:
2059        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2060        if raw_categories := payload.get("itemCategories"):
2061            for item in raw_categories:
2062                title = undefined.Undefined
2063                if raw_title := item.get("title"):
2064                    if raw_title != typedefs.Unknown:
2065                        title = raw_title
2066                if raw_hashes := item.get("itemHashes"):
2067                    hashes: collections.Sequence[int] = raw_hashes
2068
2069                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2070
2071        about = undefined.Undefined
2072        if (raw_about := payload["about"]) != typedefs.Unknown:
2073            about = raw_about
2074
2075        status = undefined.Undefined
2076        if (raw_status := payload["status"]) != typedefs.Unknown:
2077            status = raw_status
2078
2079        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2080        if raw_tips := payload.get("tips"):
2081            for raw_tip in raw_tips:
2082                if raw_tip == typedefs.Unknown:
2083                    raw_tip = undefined.Undefined
2084                tips.append(raw_tip)
2085
2086        return milestones.MilestoneContent(
2087            about=about, status=status, tips=tips, items=items_categoris
2088        )
2089
2090    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2091        name = undefined.Undefined
2092        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2093            name = raw_name
2094
2095        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2096
2097        if raw_bungie_user := payload.get("bungieNetUser"):
2098            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2099
2100        return friends.Friend(
2101            net=self._net,
2102            id=int(payload["lastSeenAsMembershipId"]),
2103            name=name,
2104            code=payload.get("bungieGlobalDisplayNameCode"),
2105            relationship=enums.Relationship(payload["relationship"]),
2106            user=bungie_user,
2107            online_status=enums.Presence(payload["onlineStatus"]),
2108            online_title=payload["onlineTitle"],
2109            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2110        )
2111
2112    def deserialize_friends(
2113        self, payload: typedefs.JSONObject
2114    ) -> collections.Sequence[friends.Friend]:
2115        mut_seq: typing.MutableSequence[friends.Friend] = []
2116        if raw_friends := payload.get("friends"):
2117            for friend in raw_friends:
2118                mut_seq.append(self.deserialize_friend(friend))
2119        return mut_seq
2120
2121    def deserialize_friend_requests(
2122        self, payload: typedefs.JSONObject
2123    ) -> friends.FriendRequestView:
2124        incoming: typing.MutableSequence[friends.Friend] = []
2125        outgoing: typing.MutableSequence[friends.Friend] = []
2126
2127        if raw_incoming_requests := payload.get("incomingRequests"):
2128            for incoming_request in raw_incoming_requests:
2129                incoming.append(self.deserialize_friend(incoming_request))
2130
2131        if raw_outgoing_requests := payload.get("outgoingRequests"):
2132            for outgoing_request in raw_outgoing_requests:
2133                outgoing.append(self.deserialize_friend(outgoing_request))
2134
2135        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)
2136
2137    def _set_fireteam_fields(
2138        self, payload: typedefs.JSONObject, total_results: typing.Optional[int] = None
2139    ) -> fireteams.Fireteam:
2140        activity_type = fireteams.FireteamActivity(payload["activityType"])
2141        return fireteams.Fireteam(
2142            id=int(payload["fireteamId"]),
2143            group_id=int(payload["groupId"]),
2144            platform=fireteams.FireteamPlatform(payload["platform"]),
2145            is_immediate=payload["isImmediate"],
2146            activity_type=activity_type,
2147            owner_id=int(payload["ownerMembershipId"]),
2148            player_slot_count=payload["playerSlotCount"],
2149            available_player_slots=payload["availablePlayerSlotCount"],
2150            available_alternate_slots=payload["availableAlternateSlotCount"],
2151            title=payload["title"],
2152            date_created=time.clean_date(payload["dateCreated"]),
2153            is_public=payload["isPublic"],
2154            locale=fireteams.FireteamLanguage(payload["locale"]),
2155            is_valid=payload["isValid"],
2156            last_modified=time.clean_date(payload["datePlayerModified"]),
2157            total_results=total_results or 0,
2158        )
2159
2160    def deserialize_fireteams(
2161        self, payload: typedefs.JSONObject
2162    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2163        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2164
2165        result: list[typedefs.JSONObject]
2166        if not (result := payload["results"]):
2167            return None
2168        for elem in result:
2169            fireteams_.append(
2170                self._set_fireteam_fields(
2171                    elem, total_results=int(payload["totalResults"])
2172                )
2173            )
2174        return fireteams_
2175
2176    def deserialize_fireteam_destiny_users(
2177        self, payload: typedefs.JSONObject
2178    ) -> fireteams.FireteamUser:
2179        destiny_obj = self.deserialize_destiny_membership(payload)
2180        # We could helpers.just return a DestinyMembership object but this is
2181        # missing the fireteam display name and id fields.
2182        return fireteams.FireteamUser(
2183            net=self._net,
2184            id=destiny_obj.id,
2185            code=destiny_obj.code,
2186            icon=destiny_obj.icon,
2187            types=destiny_obj.types,
2188            type=destiny_obj.type,
2189            is_public=destiny_obj.is_public,
2190            crossave_override=destiny_obj.crossave_override,
2191            name=destiny_obj.name,
2192            last_seen_name=destiny_obj.last_seen_name,
2193            fireteam_display_name=payload["FireteamDisplayName"],
2194            fireteam_membership_id=enums.MembershipType(
2195                payload["FireteamMembershipType"]
2196            ),
2197        )
2198
2199    def deserialize_fireteam_members(
2200        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2201    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2202        members_: list[fireteams.FireteamMember] = []
2203        if members := payload.get("Members" if not alternatives else "Alternates"):
2204            for member in members:
2205                bungie_fields = self.deserialize_partial_bungie_user(member)
2206                members_fields = fireteams.FireteamMember(
2207                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2208                    has_microphone=member["hasMicrophone"],
2209                    character_id=int(member["characterId"]),
2210                    date_joined=time.clean_date(member["dateJoined"]),
2211                    last_platform_invite_date=time.clean_date(
2212                        member["lastPlatformInviteAttemptDate"]
2213                    ),
2214                    last_platform_invite_result=int(
2215                        member["lastPlatformInviteAttemptResult"]
2216                    ),
2217                    net=self._net,
2218                    name=bungie_fields.name,
2219                    id=bungie_fields.id,
2220                    icon=bungie_fields.icon,
2221                    is_public=bungie_fields.is_public,
2222                    crossave_override=bungie_fields.crossave_override,
2223                    types=bungie_fields.types,
2224                    type=bungie_fields.type,
2225                )
2226                members_.append(members_fields)
2227        else:
2228            return None
2229        return members_
2230
2231    def deserialize_available_fireteams(
2232        self,
2233        data: typedefs.JSONObject,
2234        *,
2235        no_results: bool = False,
2236    ) -> typing.Union[
2237        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2238    ]:
2239        fireteams_: list[fireteams.AvailableFireteam] = []
2240
2241        # This needs to be used outside the results
2242        # JSON key.
2243        if no_results is True:
2244            payload = data
2245
2246        if result := payload.get("results"):
2247
2248            for fireteam in result:
2249                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2250                fireteams_fields = fireteams.AvailableFireteam(
2251                    id=found_fireteams.id,
2252                    group_id=found_fireteams.group_id,
2253                    platform=found_fireteams.platform,
2254                    activity_type=found_fireteams.activity_type,
2255                    is_immediate=found_fireteams.is_immediate,
2256                    is_public=found_fireteams.is_public,
2257                    is_valid=found_fireteams.is_valid,
2258                    owner_id=found_fireteams.owner_id,
2259                    player_slot_count=found_fireteams.player_slot_count,
2260                    available_player_slots=found_fireteams.available_player_slots,
2261                    available_alternate_slots=found_fireteams.available_alternate_slots,
2262                    title=found_fireteams.title,
2263                    date_created=found_fireteams.date_created,
2264                    locale=found_fireteams.locale,
2265                    last_modified=found_fireteams.last_modified,
2266                    total_results=found_fireteams.total_results,
2267                    members=self.deserialize_fireteam_members(payload),
2268                    alternatives=self.deserialize_fireteam_members(
2269                        payload, alternatives=True
2270                    ),
2271                )
2272            fireteams_.append(fireteams_fields)
2273            if no_results:
2274                return fireteams_fields
2275        return fireteams_
2276
2277    def deserialize_fireteam_party(
2278        self, payload: typedefs.JSONObject
2279    ) -> fireteams.FireteamParty:
2280        last_destination_hash: typing.Optional[int] = None
2281        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2282            last_destination_hash = int(raw_dest_hash)
2283
2284        return fireteams.FireteamParty(
2285            members=[
2286                self._deserialize_fireteam_party_member(member)
2287                for member in payload["partyMembers"]
2288            ],
2289            activity=self._deserialize_fireteam_party_current_activity(
2290                payload["currentActivity"]
2291            ),
2292            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2293            last_destination_hash=last_destination_hash,
2294            tracking=payload["tracking"],
2295        )
2296
2297    def _deserialize_fireteam_party_member(
2298        self, payload: typedefs.JSONObject
2299    ) -> fireteams.FireteamPartyMember:
2300
2301        status = fireteams.FireteamPartyMemberState(payload["status"])
2302        displayname: undefined.UndefinedOr[str] = undefined.Undefined
2303        if raw_name := payload.get("displayName"):
2304            displayname = raw_name
2305
2306        return fireteams.FireteamPartyMember(
2307            membership_id=int(payload["membershipId"]),
2308            emblem_hash=int(payload["emblemHash"]),
2309            status=status,
2310            display_name=displayname,
2311        )
2312
2313    def _deserialize_fireteam_party_current_activity(
2314        self, payload: typedefs.JSONObject
2315    ) -> fireteams.FireteamPartyCurrentActivity:
2316        start_date: typing.Optional[datetime.datetime] = None
2317        if raw_start_date := payload.get("startTime"):
2318            start_date = time.clean_date(raw_start_date)
2319
2320        end_date: typing.Optional[datetime.datetime] = None
2321        if raw_end_date := payload.get("endTime"):
2322            end_date = time.clean_date(raw_end_date)
2323        return fireteams.FireteamPartyCurrentActivity(
2324            start_time=start_date,
2325            end_time=end_date,
2326            score=float(payload["score"]),
2327            highest_opposing_score=float(payload["highestOpposingFactionScore"]),
2328            opponenst_count=int(payload["numberOfOpponents"]),
2329            player_count=int(payload["numberOfPlayers"]),
2330        )
2331
2332    def _deserialize_fireteam_party_settings(
2333        self, payload: typedefs.JSONObject
2334    ) -> fireteams.FireteamPartySettings:
2335        closed_reasons = enums.ClosedReasons(payload["closedReasons"])
2336        return fireteams.FireteamPartySettings(
2337            open_slots=int(payload["openSlots"]),
2338            privacy_setting=enums.PrivacySetting(int(payload["privacySetting"])),
2339            closed_reasons=closed_reasons,
2340        )
2341
2342    def deserialize_seasonal_artifact(
2343        self, payload: typedefs.JSONObject
2344    ) -> season.Artifact:
2345        if raw_artifact := payload.get("seasonalArtifact"):
2346            if points := raw_artifact.get("pointProgression"):
2347                points_prog = progressions.Progression(
2348                    hash=points["progressionHash"],
2349                    level=points["level"],
2350                    cap=points["levelCap"],
2351                    daily_limit=points["dailyLimit"],
2352                    weekly_limit=points["weeklyLimit"],
2353                    current_progress=points["currentProgress"],
2354                    daily_progress=points["dailyProgress"],
2355                    needed=points["progressToNextLevel"],
2356                    next_level=points["nextLevelAt"],
2357                )
2358
2359            if bonus := raw_artifact.get("powerBonusProgression"):
2360                power_bonus_prog = progressions.Progression(
2361                    hash=bonus["progressionHash"],
2362                    level=bonus["level"],
2363                    cap=bonus["levelCap"],
2364                    daily_limit=bonus["dailyLimit"],
2365                    weekly_limit=bonus["weeklyLimit"],
2366                    current_progress=bonus["currentProgress"],
2367                    daily_progress=bonus["dailyProgress"],
2368                    needed=bonus["progressToNextLevel"],
2369                    next_level=bonus["nextLevelAt"],
2370                )
2371            artifact = season.Artifact(
2372                net=self._net,
2373                hash=raw_artifact["artifactHash"],
2374                power_bonus=raw_artifact["powerBonus"],
2375                acquired_points=raw_artifact["pointsAcquired"],
2376                bonus=power_bonus_prog,
2377                points=points_prog,
2378            )
2379        return artifact
2380
2381    def deserialize_profile_progression(
2382        self, payload: typedefs.JSONObject
2383    ) -> profile.ProfileProgression:
2384        return profile.ProfileProgression(
2385            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2386            checklist={
2387                int(check_id): checklists
2388                for check_id, checklists in payload["data"]["checklists"].items()
2389            },
2390        )
2391
2392    def deserialize_instanced_item(
2393        self, payload: typedefs.JSONObject
2394    ) -> items.ItemInstance:
2395        damage_type_hash: typing.Optional[int] = None
2396        if raw_damagetype_hash := payload.get("damageTypeHash"):
2397            damage_type_hash = int(raw_damagetype_hash)
2398
2399        required_hashes: typing.Optional[collections.Collection[int]] = None
2400        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2401            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2402
2403        breaker_type: typing.Optional[items.ItemBreakerType] = None
2404        if raw_break_type := payload.get("breakerType"):
2405            breaker_type = items.ItemBreakerType(int(raw_break_type))
2406
2407        breaker_type_hash: typing.Optional[int] = None
2408        if raw_break_type_hash := payload.get("breakerTypeHash"):
2409            breaker_type_hash = int(raw_break_type_hash)
2410
2411        energy: typing.Optional[items.ItemEnergy] = None
2412        if raw_energy := payload.get("energy"):
2413            energy = self.deserialize_item_energy(raw_energy)
2414
2415        primary_stats = None
2416        if raw_primary_stats := payload.get("primaryStat"):
2417            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2418
2419        return items.ItemInstance(
2420            damage_type=enums.DamageType(int(payload["damageType"])),
2421            damage_type_hash=damage_type_hash,
2422            primary_stat=primary_stats,
2423            item_level=int(payload["itemLevel"]),
2424            quality=int(payload["quality"]),
2425            is_equipped=payload["isEquipped"],
2426            can_equip=payload["canEquip"],
2427            equip_required_level=int(payload["equipRequiredLevel"]),
2428            required_equip_unlock_hashes=required_hashes,
2429            cant_equip_reason=int(payload["cannotEquipReason"]),
2430            breaker_type=breaker_type,
2431            breaker_type_hash=breaker_type_hash,
2432            energy=energy,
2433        )
2434
2435    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2436        energy_hash: typing.Optional[int] = None
2437        if raw_energy_hash := payload.get("energyTypeHash"):
2438            energy_hash = int(raw_energy_hash)
2439
2440        return items.ItemEnergy(
2441            hash=energy_hash,
2442            type=items.ItemEnergyType(int(payload["energyType"])),
2443            capacity=int(payload["energyCapacity"]),
2444            used_energy=int(payload["energyUsed"]),
2445            unused_energy=int(payload["energyUnused"]),
2446        )
2447
2448    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2449        perk_hash: typing.Optional[int] = None
2450        if raw_perk_hash := payload.get("perkHash"):
2451            perk_hash = int(raw_perk_hash)
2452
2453        return items.ItemPerk(
2454            hash=perk_hash,
2455            icon=assets.Image(payload["iconPath"]),
2456            is_active=payload["isActive"],
2457            is_visible=payload["visible"],
2458        )
2459
2460    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2461        plug_hash: typing.Optional[int] = None
2462        if raw_plug_hash := payload.get("plugHash"):
2463            plug_hash = int(raw_plug_hash)
2464
2465        enable_fail_indexes: typing.Optional[list[int]] = None
2466        if raw_indexes := payload.get("enableFailIndexes"):
2467            enable_fail_indexes = [int(index) for index in raw_indexes]
2468
2469        return items.ItemSocket(
2470            plug_hash=plug_hash,
2471            is_enabled=payload["isEnabled"],
2472            enable_fail_indexes=enable_fail_indexes,
2473            is_visible=payload.get("visible"),
2474        )
2475
2476    def deserialize_item_stats_view(
2477        self, payload: typedefs.JSONObject
2478    ) -> items.ItemStatsView:
2479        return items.ItemStatsView(
2480            stat_hash=payload.get("statHash"), value=payload.get("value")
2481        )
2482
2483    def deserialize_plug_item_state(
2484        self, payload: typedefs.JSONObject
2485    ) -> items.PlugItemState:
2486        item_hash: typing.Optional[int] = None
2487        if raw_item_hash := payload.get("plugItemHash"):
2488            item_hash = int(raw_item_hash)
2489
2490        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2491        if raw_fail_indexes := payload.get("insertFailIndexes"):
2492            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2493
2494        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2495        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2496            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2497
2498        return items.PlugItemState(
2499            item_hash=item_hash,
2500            insert_fail_indexes=insert_fail_indexes,
2501            enable_fail_indexes=enable_fail_indexes,
2502            is_enabled=payload["enabled"],
2503            can_insert=payload["canInsert"],
2504        )

The base deserialization factory class for all aiobungie objects.

Highly inspired hikari entity factory used to deserialize JSON responses from the REST client and turning them into a aiobungie.crates Python classes.

Factory(net: aiobungie.traits.Netrunner)
70    def __init__(self, net: traits.Netrunner) -> None:
71        self._net = net
def deserialize_bungie_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.BungieUser:
73    def deserialize_bungie_user(self, data: typedefs.JSONObject) -> user.BungieUser:
74        return user.BungieUser(
75            id=int(data["membershipId"]),
76            created_at=time.clean_date(data["firstAccess"]),
77            name=data.get("cachedBungieGlobalDisplayName", undefined.Undefined),
78            is_deleted=data["isDeleted"],
79            about=data["about"],
80            updated_at=time.clean_date(data["lastUpdate"]),
81            psn_name=data.get("psnDisplayName", None),
82            stadia_name=data.get("stadiaDisplayName", None),
83            steam_name=data.get("steamDisplayName", None),
84            twitch_name=data.get("twitchDisplayName", None),
85            blizzard_name=data.get("blizzardDisplayName", None),
86            status=data["statusText"],
87            locale=data["locale"],
88            picture=assets.Image(path=str(data["profilePicturePath"])),
89            code=data.get("cachedBungieGlobalDisplayNameCode", None),
90            unique_name=data.get("uniqueName", None),
91            theme_id=int(data["profileTheme"]),
92            show_activity=bool(data["showActivity"]),
93            theme_name=data["profileThemeName"],
94            display_title=data["userTitleDisplay"],
95        )

Deserialize a raw JSON Bungie.net user only payload into a user object.

This only returns the Bungie.net user and not the Destiny memberships.

Parameters
Returns
def deserialize_partial_bungie_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.PartialBungieUser:
 97    def deserialize_partial_bungie_user(
 98        self, payload: typedefs.JSONObject
 99    ) -> user.PartialBungieUser:
100        return user.PartialBungieUser(
101            net=self._net,
102            types=[
103                enums.MembershipType(type_)
104                for type_ in payload.get("applicableMembershipTypes", [])
105            ],
106            name=payload.get("displayName", undefined.Undefined),
107            id=int(payload["membershipId"]),
108            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
109            is_public=payload["isPublic"],
110            icon=assets.Image(payload.get("iconPath", "")),
111            type=enums.MembershipType(payload["membershipType"]),
112        )

Deserialize a raw JSON of a partial bungieNetUserInfo.

A partial user is a bungie.net user payload with missing information from the main BungieUser object.

Parameters
Returns
def deserialize_destiny_membership( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.DestinyMembership:
114    def deserialize_destiny_membership(
115        self, payload: typedefs.JSONObject
116    ) -> user.DestinyMembership:
117        name: undefined.UndefinedOr[str] = undefined.Undefined
118        if (
119            raw_name := payload.get("bungieGlobalDisplayName", "")
120        ) and not typedefs.is_unknown(raw_name):
121            name = raw_name
122
123        return user.DestinyMembership(
124            net=self._net,
125            id=int(payload["membershipId"]),
126            name=name,
127            code=payload.get("bungieGlobalDisplayNameCode", None),
128            last_seen_name=payload.get("LastSeenDisplayName")
129            or payload.get("displayName")  # noqa: W503
130            or "",  # noqa: W503
131            type=enums.MembershipType(payload["membershipType"]),
132            is_public=payload["isPublic"],
133            crossave_override=enums.MembershipType(payload["crossSaveOverride"]),
134            icon=assets.Image(payload.get("iconPath", "")),
135            types=[
136                enums.MembershipType(type_)
137                for type_ in payload.get("applicableMembershipTypes", [])
138            ],
139        )

Deserialize a raw JSON of destinyUserInfo destiny membership information.

Parameters
Returns
  • aiobungie.crates.user.DestinyMembership: A Destiny 2 membership.
def deserialize_destiny_memberships( self, data: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.DestinyMembership]:
141    def deserialize_destiny_memberships(
142        self, data: typedefs.JSONArray
143    ) -> collections.Sequence[user.DestinyMembership]:
144        return [self.deserialize_destiny_membership(membership) for membership in data]

Deserialize a raw JSON payload/array of destinyUserInfo.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.DestinyMembership]: A sequence of Destiny 2 memberships.
def deserialize_user(self, data: dict[str, typing.Any]) -> aiobungie.crates.user.User:
146    def deserialize_user(self, data: typedefs.JSONObject) -> user.User:
147
148        primary_membership_id: typing.Optional[int] = None
149        if raw_primary_id := data.get("primaryMembershipId"):
150            primary_membership_id = int(raw_primary_id)
151
152        return user.User(
153            bungie=self.deserialize_bungie_user(data["bungieNetUser"]),
154            destiny=self.deserialize_destiny_memberships(data["destinyMemberships"]),
155            primary_membership_id=primary_membership_id,
156        )

Deserialize a raw JSON results of fetched user memberships and Bungie.net user its their id.

Parameters
Returns
def deserialize_searched_user( self, payload: dict[str, typing.Any]) -> aiobungie.crates.user.SearchableDestinyUser:
158    def deserialize_searched_user(
159        self, payload: typedefs.JSONObject
160    ) -> user.SearchableDestinyUser:
161        name: undefined.UndefinedOr[str] = undefined.Undefined
162        if (raw_name := payload["bungieGlobalDisplayName"]) and not typedefs.is_unknown(
163            raw_name
164        ):
165            name = raw_name
166
167        code: typing.Optional[int] = None
168        if raw_code := payload.get("bungieGlobalDisplayNameCode"):
169            code = int(raw_code)
170
171        bungie_id: typing.Optional[int] = None
172        if raw_bungie_id := payload.get("bungieNetMembershipId"):
173            bungie_id = int(raw_bungie_id)
174
175        return user.SearchableDestinyUser(
176            name=name,
177            code=code,
178            bungie_id=bungie_id,
179            memberships=self.deserialize_destiny_memberships(
180                payload["destinyMemberships"]
181            ),
182        )

Deserialize the results of user search details.

Parameters
Returns
def deserialize_user_credentials( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserCredentials]:
184    def deserialize_user_credentials(
185        self, payload: typedefs.JSONArray
186    ) -> collections.Sequence[user.UserCredentials]:
187        return [
188            user.UserCredentials(
189                type=enums.CredentialType(int(creds["credentialType"])),
190                display_name=creds["credentialDisplayName"],
191                is_public=creds["isPublic"],
192                self_as_string=creds.get("credentialAsString", undefined.Undefined),
193            )
194            for creds in payload
195        ]

Deserialize a JSON array of Bungie user credentials.

Parameters
Returns
@staticmethod
def set_themese_attrs( payload: list[typing.Any], /) -> Collection[aiobungie.crates.user.UserThemes]:
197    @staticmethod
198    def set_themese_attrs(
199        payload: typedefs.JSONArray, /
200    ) -> typing.Collection[user.UserThemes]:
201        return [
202            user.UserThemes(
203                id=int(entry["userThemeId"]),
204                name=entry["userThemeName"]
205                if "userThemeName" in entry
206                else undefined.Undefined,
207                description=entry["userThemeDescription"]
208                if "userThemeDescription" in entry
209                else undefined.Undefined,
210            )
211            for entry in payload
212        ]
def deserialize_user_themes( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.user.UserThemes]:
214    def deserialize_user_themes(
215        self, payload: typedefs.JSONArray
216    ) -> collections.Sequence[user.UserThemes]:
217        return list(self.set_themese_attrs(payload))

Deserialize a raw JSON array of Bungie user themes.

Parameters
Returns
  • collections.Sequence[aiobungie.crates.user.UserThemes]: A sequence of bungie user themes.
def deserialize_clan(self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.Clan:
219    def deserialize_clan(self, payload: typedefs.JSONObject) -> clans.Clan:
220
221        # This is kinda redundant
222        data = payload
223
224        # This is always outside the details.
225        current_user_map: typing.Optional[
226            collections.Mapping[str, clans.ClanMember]
227        ] = None
228        if raw_current_user_map := payload.get("currentUserMemberMap"):
229            current_user_map = {
230                membership_type: self.deserialize_clan_member(membership)
231                for membership_type, membership in raw_current_user_map.items()
232            }
233
234        try:
235            data = payload["detail"]
236        except KeyError:
237            pass
238
239        id = data["groupId"]
240        name = data["name"]
241        created_at = data["creationDate"]
242        member_count = data["memberCount"]
243        about = data["about"]
244        motto = data["motto"]
245        is_public = data["isPublic"]
246        banner = assets.Image(str(data["bannerPath"]))
247        avatar = assets.Image(str(data["avatarPath"]))
248        tags = data["tags"]
249        type = data["groupType"]
250
251        features = data["features"]
252        features_obj = clans.ClanFeatures(
253            max_members=features["maximumMembers"],
254            max_membership_types=features["maximumMembershipsOfGroupType"],
255            capabilities=features["capabilities"],
256            membership_types=features["membershipTypes"],
257            invite_permissions=features["invitePermissionOverride"],
258            update_banner_permissions=features["updateBannerPermissionOverride"],
259            update_culture_permissions=features["updateCulturePermissionOverride"],
260            join_level=features["joinLevel"],
261        )
262
263        information: typedefs.JSONObject = data["clanInfo"]
264        progression: collections.Mapping[int, progressions.Progression] = {
265            int(prog_hash): self.deserialize_progressions(prog)
266            for prog_hash, prog in information["d2ClanProgressions"].items()
267        }
268
269        founder: typedefs.NoneOr[clans.ClanMember] = None
270        if raw_founder := payload.get("founder"):
271            founder = self.deserialize_clan_member(raw_founder)
272
273        return clans.Clan(
274            net=self._net,
275            id=int(id),
276            name=name,
277            type=enums.GroupType(type),
278            created_at=time.clean_date(created_at),
279            member_count=member_count,
280            motto=motto,
281            about=about,
282            is_public=is_public,
283            banner=banner,
284            avatar=avatar,
285            tags=tags,
286            features=features_obj,
287            owner=founder,
288            progressions=progression,
289            call_sign=information["clanCallsign"],
290            banner_data=information["clanBannerData"],
291            chat_security=data["chatSecurity"],
292            conversation_id=int(data["conversationId"]),
293            allow_chat=data["allowChat"],
294            theme=data["theme"],
295            current_user_membership=current_user_map,
296        )

Deserialize a raw JSON payload of Bungie clan information.

Parameters
Returns
def deserialize_clan_member( self, data: dict[str, typing.Any], /) -> aiobungie.crates.clans.ClanMember:
298    def deserialize_clan_member(self, data: typedefs.JSONObject, /) -> clans.ClanMember:
299        destiny_user = self.deserialize_destiny_membership(data["destinyUserInfo"])
300        return clans.ClanMember(
301            net=self._net,
302            last_seen_name=destiny_user.last_seen_name,
303            id=destiny_user.id,
304            name=destiny_user.name,
305            icon=destiny_user.icon,
306            last_online=time.from_timestamp(int(data["lastOnlineStatusChange"])),
307            group_id=int(data["groupId"]),
308            joined_at=time.clean_date(data["joinDate"]),
309            types=destiny_user.types,
310            is_public=destiny_user.is_public,
311            type=destiny_user.type,
312            code=destiny_user.code,
313            is_online=data["isOnline"],
314            crossave_override=destiny_user.crossave_override,
315            bungie=self.deserialize_partial_bungie_user(data["bungieNetUserInfo"])
316            if "bungieNetUserInfo" in data
317            else None,
318            member_type=enums.ClanMemberType(int(data["memberType"])),
319        )

Deserialize a JSON payload of a clan member information.

Parameters
Returns
def deserialize_clan_members( self, data: dict[str, typing.Any], /) -> aiobungie.FlatIterator[aiobungie.crates.clans.ClanMember]:
321    def deserialize_clan_members(
322        self, data: typedefs.JSONObject, /
323    ) -> iterators.FlatIterator[clans.ClanMember]:
324        return iterators.FlatIterator(
325            [self.deserialize_clan_member(member) for member in data["results"]]
326        )

Deserialize a JSON payload of a clan members information.

Parameters
Returns
def deserialize_group_member( self, payload: dict[str, typing.Any]) -> aiobungie.crates.clans.GroupMember:
328    def deserialize_group_member(
329        self, payload: typedefs.JSONObject
330    ) -> clans.GroupMember:
331        member = payload["member"]
332        return clans.GroupMember(
333            net=self._net,
334            join_date=time.clean_date(member["joinDate"]),
335            group_id=int(member["groupId"]),
336            member_type=enums.ClanMemberType(member["memberType"]),
337            is_online=member["isOnline"],
338            last_online=time.from_timestamp(int(member["lastOnlineStatusChange"])),
339            inactive_memberships=payload.get("areAllMembershipsInactive", None),
340            member=self.deserialize_destiny_membership(member["destinyUserInfo"]),
341            group=self.deserialize_clan(payload["group"]),
342        )

Deserialize a JSON payload of group information for a member.

Parameters
Returns
def deserialize_clan_conversations( self, payload: list[typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanConversation]:
360    def deserialize_clan_conversations(
361        self, payload: typedefs.JSONArray
362    ) -> collections.Sequence[clans.ClanConversation]:
363        return [self._deserialize_clan_conversation(conv) for conv in payload]

Deserialize a JSON array of a clan conversations information.

Parameters
Returns
def deserialize_app_owner( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.ApplicationOwner:
365    def deserialize_app_owner(
366        self, payload: typedefs.JSONObject
367    ) -> application.ApplicationOwner:
368        return application.ApplicationOwner(
369            net=self._net,
370            name=payload.get("bungieGlobalDisplayName", undefined.Undefined),
371            id=int(payload["membershipId"]),
372            type=enums.MembershipType(payload["membershipType"]),
373            icon=assets.Image(str(payload["iconPath"])),
374            is_public=payload["isPublic"],
375            code=payload.get("bungieGlobalDisplayNameCode", None),
376        )

Deserialize a JSON payload of Bungie Developer portal application owner information.

Parameters
Returns
  • aiobungie.crates.application.ApplicationOwner: An application owner.
def deserialize_app( self, payload: dict[str, typing.Any]) -> aiobungie.crates.application.Application:
378    def deserialize_app(self, payload: typedefs.JSONObject) -> application.Application:
379        return application.Application(
380            id=int(payload["applicationId"]),
381            name=payload["name"],
382            link=payload["link"],
383            status=payload["status"],
384            redirect_url=payload.get("redirectUrl", None),
385            created_at=time.clean_date(str(payload["creationDate"])),
386            published_at=time.clean_date(str(payload["firstPublished"])),
387            owner=self.deserialize_app_owner(payload["team"][0]["user"]),  # type: ignore
388            scope=payload.get("scope", undefined.Undefined),
389        )

Deserialize a JSON payload of Bungie Developer portal application information.

Parameters
Returns
  • aiobungie.crates.application.Application: An application.
def deserialize_profile( self, payload: dict[str, typing.Any], /) -> Optional[aiobungie.crates.profile.Profile]:
412    def deserialize_profile(
413        self, payload: typedefs.JSONObject, /
414    ) -> typing.Optional[profile.Profile]:
415        if (raw_profile := payload.get("data")) is None:
416            return None
417
418        payload = raw_profile
419        id = int(payload["userInfo"]["membershipId"])
420        name = payload["userInfo"]["displayName"]
421        is_public = payload["userInfo"]["isPublic"]
422        type = enums.MembershipType(payload["userInfo"]["membershipType"])
423        last_played = time.clean_date(str(payload["dateLastPlayed"]))
424        character_ids = [int(cid) for cid in payload["characterIds"]]
425        power_cap = payload["currentSeasonRewardPowerCap"]
426
427        return profile.Profile(
428            id=int(id),
429            name=name,
430            is_public=is_public,
431            type=type,
432            last_played=last_played,
433            character_ids=character_ids,
434            power_cap=power_cap,
435            net=self._net,
436        )

Deserialize a JSON payload of Bungie.net profile information.

Parameters
Returns
def deserialize_profile_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileItemImpl:
438    def deserialize_profile_item(
439        self, payload: typedefs.JSONObject
440    ) -> profile.ProfileItemImpl:
441
442        instance_id: typing.Optional[int] = None
443        if raw_instance_id := payload.get("itemInstanceId"):
444            instance_id = int(raw_instance_id)
445
446        version_number: typing.Optional[int] = None
447        if raw_version := payload.get("versionNumber"):
448            version_number = int(raw_version)
449
450        transfer_status = enums.TransferStatus(payload["transferStatus"])
451
452        return profile.ProfileItemImpl(
453            net=self._net,
454            hash=payload["itemHash"],
455            quantity=payload["quantity"],
456            bind_status=enums.ItemBindStatus(payload["bindStatus"]),
457            location=enums.ItemLocation(payload["location"]),
458            bucket=payload["bucketHash"],
459            transfer_status=transfer_status,
460            lockable=payload["lockable"],
461            state=enums.ItemState(payload["state"]),
462            dismantel_permissions=payload["dismantlePermission"],
463            is_wrapper=payload["isWrapper"],
464            instance_id=instance_id,
465            version_number=version_number,
466            ornament_id=payload.get("overrideStyleItemHash"),
467        )

Deserialize a JSON payload of a singular profile component item.

Parameters
Returns
def deserialize_objectives( self, payload: dict[str, typing.Any]) -> aiobungie.crates.records.Objective:
469    def deserialize_objectives(self, payload: typedefs.JSONObject) -> records.Objective:
470        return records.Objective(
471            net=self._net,
472            hash=payload["objectiveHash"],
473            visible=payload["visible"],
474            complete=payload["complete"],
475            completion_value=payload["completionValue"],
476            progress=payload.get("progress"),
477            destination_hash=payload.get("destinationHash"),
478            activity_hash=payload.get("activityHash"),
479        )

Deserialize a JSON payload of an objective found in a record profile component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
  • aiobungie.crates.records.Objective: A record objective object.
def deserialize_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, **nodes: int) -> aiobungie.crates.records.Record:
481    def deserialize_records(
482        self,
483        payload: typedefs.JSONObject,
484        scores: typing.Optional[records.RecordScores] = None,
485        **nodes: int,
486    ) -> records.Record:
487        objectives: typing.Optional[list[records.Objective]] = None
488        interval_objectives: typing.Optional[list[records.Objective]] = None
489        record_state: typedefs.IntAnd[records.RecordState]
490
491        record_state = records.RecordState(payload["state"])
492
493        if raw_objs := payload.get("objectives"):
494            objectives = [self.deserialize_objectives(obj) for obj in raw_objs]
495
496        if raw_interval_objs := payload.get("intervalObjectives"):
497            interval_objectives = [
498                self.deserialize_objectives(obj) for obj in raw_interval_objs
499            ]
500
501        return records.Record(
502            scores=scores,
503            categories_node_hash=nodes.get("categories_hash", undefined.Undefined),
504            seals_node_hash=nodes.get("seals_hash", undefined.Undefined),
505            state=record_state,
506            objectives=objectives,
507            interval_objectives=interval_objectives,
508            redeemed_count=payload.get("intervalsRedeemedCount", 0),
509            completion_times=payload.get("completedCount", None),
510            reward_visibility=payload.get("rewardVisibilty", None),
511        )

Deserialize a JSON object of a profile record component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
  • scores (typing.Optional[records.RecordScores]): The records scores object. This exists only to keep the signature of aiobungie.crates.CharacterRecord with the record object. As it will always be None in that object.
  • **nodes (int): An int kwargs use to grab the node hashes while deserializing components.
Returns
  • aiobungie.records.Record: A standard implementation of a profile record component.
def deserialize_character_records( self, payload: dict[str, typing.Any], scores: Optional[aiobungie.crates.records.RecordScores] = None, record_hashes: Optional[list[int]] = None) -> aiobungie.crates.records.CharacterRecord:
513    def deserialize_character_records(
514        self,
515        payload: typedefs.JSONObject,
516        scores: typing.Optional[records.RecordScores] = None,
517        record_hashes: typing.Optional[list[int]] = None,
518    ) -> records.CharacterRecord:
519
520        record = self.deserialize_records(payload, scores)
521        return records.CharacterRecord(
522            scores=scores,
523            categories_node_hash=record.categories_node_hash,
524            seals_node_hash=record.seals_node_hash,
525            state=record.state,
526            objectives=record.objectives,
527            interval_objectives=record.interval_objectives,
528            redeemed_count=payload.get("intervalsRedeemedCount", 0),
529            completion_times=payload.get("completedCount"),
530            reward_visibility=payload.get("rewardVisibilty"),
531            record_hashes=record_hashes or [],
532        )

Deserialize a JSON object of a profile character record component.

This almost does the same this as deserialize_records but has more fields which can only be found in a character record.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON object payload
Returns
  • aiobungie.records.CharacterRecord: A standard implementation of a profile character record component.
def deserialize_character_dye(self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Dye:
534    def deserialize_character_dye(self, payload: typedefs.JSONObject) -> character.Dye:
535        return character.Dye(
536            channel_hash=payload["channelHash"], dye_hash=payload["dyeHash"]
537        )

Deserialize a JSON payload of a character's dye information.

Parameters
Returns
  • aiobungie.crates.character.Dye: Information about a character dye object.
def deserialize_character_customization( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CustomizationOptions:
539    def deserialize_character_customization(
540        self, payload: typedefs.JSONObject
541    ) -> character.CustomizationOptions:
542        return character.CustomizationOptions(
543            personality=payload["personality"],
544            face=payload["face"],
545            skin_color=payload["skinColor"],
546            lip_color=payload["lipColor"],
547            eye_color=payload["eyeColor"],
548            hair_colors=payload.get("hairColors", []),
549            feature_colors=payload.get("featureColors", []),
550            decal_color=payload["decalColor"],
551            wear_helmet=payload["wearHelmet"],
552            hair_index=payload["hairIndex"],
553            feature_index=payload["featureIndex"],
554            decal_index=payload["decalIndex"],
555        )

Deserialize a JSON payload of a character customization information found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.CustomizationOptions: Information about a character customs object.
def deserialize_character_minimal_equipments( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.MinimalEquipments:
557    def deserialize_character_minimal_equipments(
558        self, payload: typedefs.JSONObject
559    ) -> character.MinimalEquipments:
560        dyes = None
561        if raw_dyes := payload.get("dyes"):
562            if raw_dyes:
563                dyes = [self.deserialize_character_dye(dye) for dye in raw_dyes]
564        return character.MinimalEquipments(
565            net=self._net, item_hash=payload["itemHash"], dyes=dyes
566        )

Deserialize a singular JSON peer view of equipment found in character render data profile component.

Parameters
Returns
  • aiobungie.crates.character.MinimalEquipments: A minimal equipment object.
def deserialize_character_render_data( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.character.RenderedData:
568    def deserialize_character_render_data(
569        self, payload: typedefs.JSONObject, /
570    ) -> character.RenderedData:
571        return character.RenderedData(
572            net=self._net,
573            customization=self.deserialize_character_customization(
574                payload["customization"]
575            ),
576            custom_dyes=[
577                self.deserialize_character_dye(dye)
578                for dye in payload["customDyes"]
579                if dye
580            ],
581            equipment=[
582                self.deserialize_character_minimal_equipments(equipment)
583                for equipment in payload["peerView"]["equipment"]
584            ],
585        )

Deserialize a JSON payload of a profile character render data component.

Parameters
Returns
def deserialize_available_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AvailableActivity:
587    def deserialize_available_activity(
588        self, payload: typedefs.JSONObject
589    ) -> activity.AvailableActivity:
590        return activity.AvailableActivity(
591            hash=payload["activityHash"],
592            is_new=payload["isNew"],
593            is_completed=payload["isCompleted"],
594            is_visible=payload["isVisible"],
595            display_level=payload.get("displayLevel"),
596            recommended_light=payload.get("recommendedLight"),
597            difficulty=activity.Difficulty(payload["difficultyTier"]),
598            can_join=payload["canJoin"],
599            can_lead=payload["canLead"],
600        )

Deserialize a JSON payload of an available activities.

This method is used to deserialize an array of aiobungie.crates.CharacterActivity.available_activities.

Parameters
Returns
def deserialize_character_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.CharacterActivity:
602    def deserialize_character_activity(
603        self, payload: typedefs.JSONObject
604    ) -> activity.CharacterActivity:
605        current_mode: typing.Optional[enums.GameMode] = None
606        if raw_current_mode := payload.get("currentActivityModeType"):
607            current_mode = enums.GameMode(raw_current_mode)
608
609        current_mode_types: typing.Optional[collections.Sequence[enums.GameMode]] = None
610        if raw_current_modes := payload.get("currentActivityModeTypes"):
611            current_mode_types = [enums.GameMode(type_) for type_ in raw_current_modes]
612
613        return activity.CharacterActivity(
614            date_started=time.clean_date(payload["dateActivityStarted"]),
615            current_hash=payload["currentActivityHash"],
616            current_mode_hash=payload["currentActivityModeHash"],
617            current_mode=current_mode,
618            current_mode_hashes=payload.get("currentActivityModeHashes"),
619            current_mode_types=current_mode_types,
620            current_playlist_hash=payload.get("currentPlaylistActivityHash"),
621            last_story_hash=payload["lastCompletedStoryHash"],
622            available_activities=[
623                self.deserialize_available_activity(activity_)
624                for activity_ in payload["availableActivities"]
625            ],
626        )

Deserialize a JSON payload of character activity profile component.

Parameters
Returns
def deserialize_profile_items( self, payload: dict[str, typing.Any], /) -> list[aiobungie.crates.profile.ProfileItemImpl]:
628    def deserialize_profile_items(
629        self, payload: typedefs.JSONObject, /
630    ) -> list[profile.ProfileItemImpl]:
631        return [self.deserialize_profile_item(item) for item in payload["items"]]

Deserialize a JSON payload of profile items component information.

This may deserialize profileInventories or profileCurrencies or any other alternatives.

Parameters
Returns
def deserialize_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.progressions.Progression:
674    def deserialize_progressions(
675        self, payload: typedefs.JSONObject
676    ) -> progressions.Progression:
677        return progressions.Progression(
678            hash=int(payload["progressionHash"]),
679            level=int(payload["level"]),
680            cap=int(payload["levelCap"]),
681            daily_limit=int(payload["dailyLimit"]),
682            weekly_limit=int(payload["weeklyLimit"]),
683            current_progress=int(payload["currentProgress"]),
684            daily_progress=int(payload["dailyProgress"]),
685            needed=int(payload["progressToNextLevel"]),
686            next_level=int(payload["nextLevelAt"]),
687        )
def deserialize_milestone( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.Milestone:
775    def deserialize_milestone(
776        self, payload: typedefs.JSONObject
777    ) -> milestones.Milestone:
778        start_date: typing.Optional[datetime.datetime] = None
779        if raw_start_date := payload.get("startDate"):
780            start_date = time.clean_date(raw_start_date)
781
782        end_date: typing.Optional[datetime.datetime] = None
783        if raw_end_date := payload.get("endDate"):
784            end_date = time.clean_date(raw_end_date)
785
786        rewards: typing.Optional[
787            collections.Collection[milestones.MilestoneReward]
788        ] = None
789        if raw_rewards := payload.get("rewards"):
790            rewards = [
791                self._deserialize_milestone_rewards(reward) for reward in raw_rewards
792            ]
793
794        activities: typing.Optional[
795            collections.Sequence[milestones.MilestoneActivity]
796        ] = None
797        if raw_activities := payload.get("activities"):
798            activities = [
799                self._deserialize_milestone_activity(active)
800                for active in raw_activities
801            ]
802
803        quests: typing.Optional[collections.Sequence[milestones.MilestoneQuest]] = None
804        if raw_quests := payload.get("availableQuests"):
805            quests = [
806                self._deserialize_milestone_available_quest(quest)
807                for quest in raw_quests
808            ]
809
810        vendors: typing.Optional[
811            collections.Sequence[milestones.MilestoneVendor]
812        ] = None
813        if raw_vendors := payload.get("vendors"):
814            vendors = [
815                milestones.MilestoneVendor(
816                    vendor_hash=vendor["vendorHash"],
817                    preview_itemhash=vendor.get("previewItemHash"),
818                )
819                for vendor in raw_vendors
820            ]
821
822        return milestones.Milestone(
823            hash=payload["milestoneHash"],
824            start_date=start_date,
825            end_date=end_date,
826            order=payload["order"],
827            rewards=rewards,
828            available_quests=quests,
829            activities=activities,
830            vendors=vendors,
831        )
def deserialize_characters( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.Character]:
848    def deserialize_characters(
849        self, payload: typedefs.JSONObject
850    ) -> collections.Mapping[int, character.Character]:
851        return {
852            int(char_id): self._set_character_attrs(char)
853            for char_id, char in payload["data"].items()
854        }
def deserialize_character( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.Character:
856    def deserialize_character(
857        self, payload: typedefs.JSONObject
858    ) -> character.Character:
859        return self._set_character_attrs(payload)
def deserialize_character_equipments( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, collections.abc.Sequence[aiobungie.crates.profile.ProfileItemImpl]]:
861    def deserialize_character_equipments(
862        self, payload: typedefs.JSONObject
863    ) -> collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]:
864        return {
865            int(char_id): self.deserialize_profile_items(item)
866            for char_id, item in payload["data"].items()
867        }
def deserialize_character_activities( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.activity.CharacterActivity]:
869    def deserialize_character_activities(
870        self, payload: typedefs.JSONObject
871    ) -> collections.Mapping[int, activity.CharacterActivity]:
872        return {
873            int(char_id): self.deserialize_character_activity(data)
874            for char_id, data in payload["data"].items()
875        }
def deserialize_characters_render_data( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.RenderedData]:
877    def deserialize_characters_render_data(
878        self, payload: typedefs.JSONObject
879    ) -> collections.Mapping[int, character.RenderedData]:
880        return {
881            int(char_id): self.deserialize_character_render_data(data)
882            for char_id, data in payload["data"].items()
883        }
def deserialize_character_progressions( self, payload: dict[str, typing.Any]) -> aiobungie.crates.character.CharacterProgression:
885    def deserialize_character_progressions(
886        self, payload: typedefs.JSONObject
887    ) -> character.CharacterProgression:
888        progressions_ = {
889            int(prog_id): self.deserialize_progressions(prog)
890            for prog_id, prog in payload["progressions"].items()
891        }
892
893        factions = {
894            int(faction_id): self._deserialize_factions(faction)
895            for faction_id, faction in payload["factions"].items()
896        }
897
898        milestones_ = {
899            int(milestone_hash): self.deserialize_milestone(milestone)
900            for milestone_hash, milestone in payload["milestones"].items()
901        }
902
903        uninstanced_item_objectives = {
904            int(item_hash): [self.deserialize_objectives(ins) for ins in obj]
905            for item_hash, obj in payload["uninstancedItemObjectives"].items()
906        }
907
908        artifact = payload["seasonalArtifact"]
909        seasonal_artifact = season.CharacterScopedArtifact(
910            hash=artifact["artifactHash"],
911            points_used=artifact["pointsUsed"],
912            reset_count=artifact["resetCount"],
913            tiers=[
914                self._deserialize_artifact_tiers(tier) for tier in artifact["tiers"]
915            ],
916        )
917        checklists = payload["checklists"]
918
919        return character.CharacterProgression(
920            progressions=progressions_,
921            factions=factions,
922            checklists=checklists,
923            milestones=milestones_,
924            seasonal_artifact=seasonal_artifact,
925            uninstanced_item_objectives=uninstanced_item_objectives,
926        )
def deserialize_character_progressions_mapping( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.character.CharacterProgression]:
928    def deserialize_character_progressions_mapping(
929        self, payload: typedefs.JSONObject
930    ) -> collections.Mapping[int, character.CharacterProgression]:
931        character_progressions: collections.Mapping[
932            int, character.CharacterProgression
933        ] = {}
934        for char_id, data in payload["data"].items():
935            # A little hack to stop mypy complaining about Mapping <-> dict
936            character_progressions[int(char_id)] = self.deserialize_character_progressions(data)  # type: ignore[index]
937        return character_progressions
def deserialize_characters_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.CharacterRecord]:
939    def deserialize_characters_records(
940        self,
941        payload: typedefs.JSONObject,
942    ) -> collections.Mapping[int, records.CharacterRecord]:
943
944        return {
945            int(rec_id): self.deserialize_character_records(
946                rec, record_hashes=payload.get("featuredRecordHashes")
947            )
948            for rec_id, rec in payload["records"].items()
949        }
def deserialize_profile_records( self, payload: dict[str, typing.Any]) -> collections.abc.Mapping[int, aiobungie.crates.records.Record]:
951    def deserialize_profile_records(
952        self, payload: typedefs.JSONObject
953    ) -> collections.Mapping[int, records.Record]:
954        raw_profile_records = payload["data"]
955        scores = records.RecordScores(
956            current_score=raw_profile_records["score"],
957            legacy_score=raw_profile_records["legacyScore"],
958            lifetime_score=raw_profile_records["lifetimeScore"],
959        )
960        return {
961            int(record_id): self.deserialize_records(
962                record,
963                scores,
964                categories_hash=raw_profile_records["recordCategoriesRootNodeHash"],
965                seals_hash=raw_profile_records["recordSealsRootNodeHash"],
966            )
967            for record_id, record in raw_profile_records["records"].items()
968        }
def deserialize_craftables_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CraftablesComponent:
1005    def deserialize_craftables_component(
1006        self, payload: typedefs.JSONObject
1007    ) -> components.CraftablesComponent:
1008        return components.CraftablesComponent(
1009            net=self._net,
1010            craftables={
1011                int(item_id): self._deserialize_craftable_item(item)
1012                for item_id, item in payload["craftables"].items()
1013                if item is not None
1014            },
1015            crafting_root_node_hash=payload["craftingRootNodeHash"],
1016        )
def deserialize_components( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.Component:
1018    def deserialize_components(  # noqa: C901 Too complex.
1019        self, payload: typedefs.JSONObject
1020    ) -> components.Component:
1021
1022        profile_: typing.Optional[profile.Profile] = None
1023        if raw_profile := payload.get("profile"):
1024            profile_ = self.deserialize_profile(raw_profile)
1025
1026        profile_progression: typing.Optional[profile.ProfileProgression] = None
1027        if raw_profile_progression := payload.get("profileProgression"):
1028            profile_progression = self.deserialize_profile_progression(
1029                raw_profile_progression
1030            )
1031
1032        profile_currencies: typing.Optional[
1033            collections.Sequence[profile.ProfileItemImpl]
1034        ] = None
1035        if raw_profile_currencies := payload.get("profileCurrencies"):
1036            if "data" in raw_profile_currencies:
1037                profile_currencies = self.deserialize_profile_items(
1038                    raw_profile_currencies["data"]
1039                )
1040
1041        profile_inventories: typing.Optional[
1042            collections.Sequence[profile.ProfileItemImpl]
1043        ] = None
1044        if raw_profile_inventories := payload.get("profileInventory"):
1045            if "data" in raw_profile_inventories:
1046                profile_inventories = self.deserialize_profile_items(
1047                    raw_profile_inventories["data"]
1048                )
1049
1050        profile_records: typing.Optional[
1051            collections.Mapping[int, records.Record]
1052        ] = None
1053
1054        if raw_profile_records_ := payload.get("profileRecords"):
1055            profile_records = self.deserialize_profile_records(raw_profile_records_)
1056
1057        characters: typing.Optional[typing.Mapping[int, character.Character]] = None
1058        if raw_characters := payload.get("characters"):
1059            characters = self.deserialize_characters(raw_characters)
1060
1061        character_records: typing.Optional[
1062            collections.Mapping[int, records.CharacterRecord]
1063        ] = None
1064
1065        if raw_character_records := payload.get("characterRecords"):
1066            # Had to do it in two steps..
1067            to_update: typedefs.JSONObject = {}
1068            for _, data in raw_character_records["data"].items():
1069                for record_id, record in data.items():
1070                    to_update[record_id] = record
1071
1072            character_records = {
1073                int(rec_id): self.deserialize_character_records(
1074                    rec, record_hashes=to_update.get("featuredRecordHashes")
1075                )
1076                for rec_id, rec in to_update["records"].items()
1077            }
1078
1079        character_equipments: typing.Optional[
1080            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1081        ] = None
1082        if raw_character_equips := payload.get("characterEquipment"):
1083            character_equipments = self.deserialize_character_equipments(
1084                raw_character_equips
1085            )
1086
1087        character_inventories: typing.Optional[
1088            collections.Mapping[int, collections.Sequence[profile.ProfileItemImpl]]
1089        ] = None
1090        if raw_character_inventories := payload.get("characterInventories"):
1091            if "data" in raw_character_inventories:
1092                character_inventories = self.deserialize_character_equipments(
1093                    raw_character_inventories
1094                )
1095
1096        character_activities: typing.Optional[
1097            collections.Mapping[int, activity.CharacterActivity]
1098        ] = None
1099        if raw_char_acts := payload.get("characterActivities"):
1100            character_activities = self.deserialize_character_activities(raw_char_acts)
1101
1102        character_render_data: typing.Optional[
1103            collections.Mapping[int, character.RenderedData]
1104        ] = None
1105        if raw_character_render_data := payload.get("characterRenderData"):
1106            character_render_data = self.deserialize_characters_render_data(
1107                raw_character_render_data
1108            )
1109
1110        character_progressions: typing.Optional[
1111            collections.Mapping[int, character.CharacterProgression]
1112        ] = None
1113
1114        if raw_character_progressions := payload.get("characterProgressions"):
1115            character_progressions = self.deserialize_character_progressions_mapping(
1116                raw_character_progressions
1117            )
1118
1119        profile_string_vars: typing.Optional[collections.Mapping[int, int]] = None
1120        if raw_profile_string_vars := payload.get("profileStringVariables"):
1121            profile_string_vars = raw_profile_string_vars["data"]["integerValuesByHash"]
1122
1123        character_string_vars: typing.Optional[
1124            collections.Mapping[int, collections.Mapping[int, int]]
1125        ] = None
1126        if raw_character_string_vars := payload.get("characterStringVariables"):
1127            character_string_vars = {
1128                int(char_id): data["integerValuesByHash"]
1129                for char_id, data in raw_character_string_vars["data"].items()
1130            }
1131
1132        metrics: typing.Optional[
1133            collections.Sequence[
1134                collections.Mapping[
1135                    int, tuple[bool, typing.Optional[records.Objective]]
1136                ]
1137            ]
1138        ] = None
1139        root_node_hash: typing.Optional[int] = None
1140
1141        if raw_metrics := payload.get("metrics"):
1142            root_node_hash = raw_metrics["data"]["metricsRootNodeHash"]
1143            metrics = [
1144                {
1145                    int(metrics_hash): (
1146                        data["invisible"],
1147                        self.deserialize_objectives(data["objectiveProgress"])
1148                        if "objectiveProgress" in data
1149                        else None,
1150                    )
1151                    for metrics_hash, data in raw_metrics["data"]["metrics"].items()
1152                }
1153            ]
1154        transitory: typing.Optional[fireteams.FireteamParty] = None
1155        if raw_transitory := payload.get("profileTransitoryData"):
1156            if "data" in raw_transitory:
1157                transitory = self.deserialize_fireteam_party(raw_transitory["data"])
1158
1159        item_components: typing.Optional[components.ItemsComponent] = None
1160        if raw_item_components := payload.get("itemComponents"):
1161            item_components = self.deserialize_items_component(raw_item_components)
1162
1163        profile_plugsets: typing.Optional[
1164            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1165        ] = None
1166
1167        if raw_profile_plugs := payload.get("profilePlugSets"):
1168            profile_plugsets = {
1169                int(index): [self.deserialize_plug_item_state(state) for state in data]
1170                for index, data in raw_profile_plugs["data"]["plugs"].items()
1171            }
1172
1173        character_plugsets: typing.Optional[
1174            collections.Mapping[
1175                int, collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1176            ]
1177        ] = None
1178        if raw_char_plugsets := payload.get("characterPlugSets"):
1179            character_plugsets = {
1180                int(char_id): {
1181                    int(index): [
1182                        self.deserialize_plug_item_state(state) for state in data
1183                    ]
1184                    for index, data in inner["plugs"].items()
1185                }
1186                for char_id, inner in raw_char_plugsets["data"].items()
1187            }
1188
1189        character_collectibles: typing.Optional[
1190            collections.Mapping[int, items.Collectible]
1191        ] = None
1192        if raw_character_collectibles := payload.get("characterCollectibles"):
1193            character_collectibles = {
1194                int(char_id): self._deserialize_collectible(data)
1195                for char_id, data in raw_character_collectibles["data"].items()
1196            }
1197
1198        profile_collectibles: typing.Optional[items.Collectible] = None
1199        if raw_profile_collectibles := payload.get("profileCollectibles"):
1200            profile_collectibles = self._deserialize_collectible(
1201                raw_profile_collectibles["data"]
1202            )
1203
1204        profile_nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1205        if raw_profile_nodes := payload.get("profilePresentationNodes"):
1206            profile_nodes = {
1207                int(node_hash): self._deserialize_node(node)
1208                for node_hash, node in raw_profile_nodes["data"]["nodes"].items()
1209            }
1210
1211        character_nodes: typing.Optional[
1212            collections.Mapping[int, collections.Mapping[int, records.Node]]
1213        ] = None
1214        if raw_character_nodes := payload.get("characterPresentationNodes"):
1215            character_nodes = {
1216                int(char_id): {
1217                    int(node_hash): self._deserialize_node(node)
1218                    for node_hash, node in each_character["nodes"].items()
1219                }
1220                for char_id, each_character in raw_character_nodes["data"].items()
1221            }
1222
1223        platform_silver: typing.Optional[
1224            collections.Mapping[str, profile.ProfileItemImpl]
1225        ] = None
1226        if raw_platform_silver := payload.get("platformSilver"):
1227            if "data" in raw_platform_silver:
1228                platform_silver = {
1229                    platform_name: self.deserialize_profile_item(item)
1230                    for platform_name, item in raw_platform_silver["data"][
1231                        "platformSilver"
1232                    ].items()
1233                }
1234
1235        character_currency_lookups: typing.Optional[
1236            collections.Mapping[int, collections.Sequence[items.Currency]]
1237        ] = None
1238        if raw_char_lookups := payload.get("characterCurrencyLookups"):
1239            if "data" in raw_char_lookups:
1240                character_currency_lookups = {
1241                    int(char_id): self._deserialize_currencies(currencie)
1242                    for char_id, currencie in raw_char_lookups["data"].items()
1243                }
1244
1245        character_craftables: typing.Optional[
1246            collections.Mapping[int, components.CraftablesComponent]
1247        ] = None
1248        if raw_character_craftables := payload.get("characterCraftables"):
1249
1250            if "data" in raw_character_craftables:
1251                character_craftables = {
1252                    int(char_id): self.deserialize_craftables_component(craftable)
1253                    for char_id, craftable in raw_character_craftables["data"].items()
1254                }
1255
1256        return components.Component(
1257            profiles=profile_,
1258            profile_progression=profile_progression,
1259            profile_currencies=profile_currencies,
1260            profile_inventories=profile_inventories,
1261            profile_records=profile_records,
1262            characters=characters,
1263            character_records=character_records,
1264            character_equipments=character_equipments,
1265            character_inventories=character_inventories,
1266            character_activities=character_activities,
1267            character_render_data=character_render_data,
1268            character_progressions=character_progressions,
1269            profile_string_variables=profile_string_vars,
1270            character_string_variables=character_string_vars,
1271            metrics=metrics,
1272            root_node_hash=root_node_hash,
1273            transitory=transitory,
1274            item_components=item_components,
1275            profile_plugsets=profile_plugsets,
1276            character_plugsets=character_plugsets,
1277            character_collectibles=character_collectibles,
1278            profile_collectibles=profile_collectibles,
1279            profile_nodes=profile_nodes,
1280            character_nodes=character_nodes,
1281            platform_silver=platform_silver,
1282            character_currency_lookups=character_currency_lookups,
1283            character_craftables=character_craftables,
1284        )

Deserialize a JSON payload of Bungie.net profile components information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_items_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.ItemsComponent:
1286    def deserialize_items_component(
1287        self, payload: typedefs.JSONObject
1288    ) -> components.ItemsComponent:
1289        instances: typing.Optional[
1290            collections.Sequence[collections.Mapping[int, items.ItemInstance]]
1291        ] = None
1292        if raw_instances := payload.get("instances"):
1293            instances = [
1294                {
1295                    int(ins_id): self.deserialize_instanced_item(item)
1296                    for ins_id, item in raw_instances["data"].items()
1297                }
1298            ]
1299
1300        render_data: typing.Optional[
1301            collections.Mapping[int, tuple[bool, dict[int, int]]]
1302        ] = None
1303        if raw_render_data := payload.get("renderData"):
1304            render_data = {
1305                int(ins_id): (data["useCustomDyes"], data["artRegions"])
1306                for ins_id, data in raw_render_data["data"].items()
1307            }
1308
1309        stats: typing.Optional[collections.Mapping[int, items.ItemStatsView]] = None
1310        if raw_stats := payload.get("stats"):
1311            builder: collections.Mapping[int, items.ItemStatsView] = {}
1312            for ins_id, stat in raw_stats["data"].items():
1313                for _, items_ in stat.items():
1314                    builder[int(ins_id)] = self.deserialize_item_stats_view(items_)  # type: ignore[index]
1315            stats = builder
1316
1317        sockets: typing.Optional[
1318            collections.Mapping[int, collections.Sequence[items.ItemSocket]]
1319        ] = None
1320        if raw_sockets := payload.get("sockets"):
1321            sockets = {
1322                int(ins_id): [
1323                    self.deserialize_item_socket(socket) for socket in item["sockets"]
1324                ]
1325                for ins_id, item in raw_sockets["data"].items()
1326            }
1327
1328        objeectives: typing.Optional[
1329            collections.Mapping[int, collections.Sequence[records.Objective]]
1330        ] = None
1331        if raw_objectives := payload.get("objectives"):
1332            objeectives = {
1333                int(ins_id): [self.deserialize_objectives(objective)]
1334                for ins_id, data in raw_objectives["data"].items()
1335                for objective in data["objectives"]
1336            }
1337
1338        perks: typing.Optional[
1339            collections.Mapping[int, collections.Collection[items.ItemPerk]]
1340        ] = None
1341        if raw_perks := payload.get("perks"):
1342            perks = {
1343                int(ins_id): [
1344                    self.deserialize_item_perk(perk) for perk in item["perks"]
1345                ]
1346                for ins_id, item in raw_perks["data"].items()
1347            }
1348
1349        plug_states: typing.Optional[collections.Sequence[items.PlugItemState]] = None
1350        if raw_plug_states := payload.get("plugStates"):
1351            pending_states: list[items.PlugItemState] = []
1352            for _, plug in raw_plug_states["data"].items():
1353                pending_states.append(self.deserialize_plug_item_state(plug))
1354            plug_states = pending_states
1355
1356        reusable_plugs: typing.Optional[
1357            collections.Mapping[int, collections.Sequence[items.PlugItemState]]
1358        ] = None
1359        if raw_re_plugs := payload.get("reusablePlugs"):
1360            reusable_plugs = {
1361                int(ins_id): [
1362                    self.deserialize_plug_item_state(state) for state in inner
1363                ]
1364                for ins_id, plug in raw_re_plugs["data"].items()
1365                for inner in list(plug["plugs"].values())
1366            }
1367
1368        plug_objectives: typing.Optional[
1369            collections.Mapping[
1370                int, collections.Mapping[int, collections.Collection[records.Objective]]
1371            ]
1372        ] = None
1373        if raw_plug_objectives := payload.get("plugObjectives"):
1374            plug_objectives = {
1375                int(ins_id): {
1376                    int(obj_hash): [self.deserialize_objectives(obj) for obj in objs]
1377                    for obj_hash, objs in inner["objectivesPerPlug"].items()
1378                }
1379                for ins_id, inner in raw_plug_objectives["data"].items()
1380            }
1381
1382        return components.ItemsComponent(
1383            sockets=sockets,
1384            stats=stats,
1385            render_data=render_data,
1386            instances=instances,
1387            objectives=objeectives,
1388            perks=perks,
1389            plug_states=plug_states,
1390            reusable_plugs=reusable_plugs,
1391            plug_objectives=plug_objectives,
1392        )

Deserialize a JSON objects within the itemComponents key.`

def deserialize_character_component( self, payload: dict[str, typing.Any]) -> aiobungie.crates.components.CharacterComponent:
1394    def deserialize_character_component(  # type: ignore[call-arg]
1395        self, payload: typedefs.JSONObject
1396    ) -> components.CharacterComponent:
1397
1398        character_: typing.Optional[character.Character] = None
1399        if raw_singuler_character := payload.get("character"):
1400            character_ = self.deserialize_character(raw_singuler_character["data"])
1401
1402        inventory: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1403        if raw_inventory := payload.get("inventory"):
1404            if "data" in raw_inventory:
1405                inventory = self.deserialize_profile_items(raw_inventory["data"])
1406
1407        activities: typing.Optional[activity.CharacterActivity] = None
1408        if raw_activities := payload.get("activities"):
1409            activities = self.deserialize_character_activity(raw_activities["data"])
1410
1411        equipment: typing.Optional[collections.Sequence[profile.ProfileItemImpl]] = None
1412        if raw_equipments := payload.get("equipment"):
1413            equipment = self.deserialize_profile_items(raw_equipments["data"])
1414
1415        progressions_: typing.Optional[character.CharacterProgression] = None
1416        if raw_progressions := payload.get("progressions"):
1417            progressions_ = self.deserialize_character_progressions(
1418                raw_progressions["data"]
1419            )
1420
1421        render_data: typing.Optional[character.RenderedData] = None
1422        if raw_render_data := payload.get("renderData"):
1423            render_data = self.deserialize_character_render_data(
1424                raw_render_data["data"]
1425            )
1426
1427        character_records: typing.Optional[
1428            collections.Mapping[int, records.CharacterRecord]
1429        ] = None
1430        if raw_char_records := payload.get("records"):
1431            character_records = self.deserialize_characters_records(
1432                raw_char_records["data"]
1433            )
1434
1435        item_components: typing.Optional[components.ItemsComponent] = None
1436        if raw_item_components := payload.get("itemComponents"):
1437            item_components = self.deserialize_items_component(raw_item_components)
1438
1439        nodes: typing.Optional[collections.Mapping[int, records.Node]] = None
1440        if raw_nodes := payload.get("presentationNodes"):
1441            nodes = {
1442                int(node_hash): self._deserialize_node(node)
1443                for node_hash, node in raw_nodes["data"]["nodes"].items()
1444            }
1445
1446        collectibles: typing.Optional[items.Collectible] = None
1447        if raw_collectibles := payload.get("collectibles"):
1448            collectibles = self._deserialize_collectible(raw_collectibles["data"])
1449
1450        currency_lookups: typing.Optional[collections.Sequence[items.Currency]] = None
1451        if raw_currencies := payload.get("currencyLookups"):
1452            if "data" in raw_currencies:
1453                currency_lookups = self._deserialize_currencies(raw_currencies)
1454
1455        return components.CharacterComponent(
1456            activities=activities,
1457            equipment=equipment,
1458            inventory=inventory,
1459            progressions=progressions_,
1460            render_data=render_data,
1461            character=character_,
1462            character_records=character_records,
1463            profile_records=None,
1464            item_components=item_components,
1465            currency_lookups=currency_lookups,
1466            collectibles=collectibles,
1467            nodes=nodes,
1468        )

Deserialize a JSON payload of Destiny 2 character component.

Parameters
Returns
def deserialize_inventory_results( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.entity.SearchableEntity]:
1496    def deserialize_inventory_results(
1497        self, payload: typedefs.JSONObject
1498    ) -> iterators.FlatIterator[entity.SearchableEntity]:
1499        suggested_words: list[str] = payload["suggestedWords"]
1500
1501        def _check_unknown(s: str) -> undefined.UndefinedOr[str]:
1502            return s if not typedefs.is_unknown(s) else undefined.Undefined
1503
1504        return iterators.FlatIterator(
1505            [
1506                entity.SearchableEntity(
1507                    net=self._net,
1508                    hash=data["hash"],
1509                    entity_type=data["entityType"],
1510                    weight=data["weight"],
1511                    suggested_words=suggested_words,
1512                    name=data["displayProperties"]["name"],
1513                    has_icon=data["displayProperties"]["hasIcon"],
1514                    description=_check_unknown(
1515                        data["displayProperties"]["description"]
1516                    ),
1517                    icon=assets.Image(data["displayProperties"]["icon"]),
1518                )
1519                for data in payload["results"]["results"]
1520            ]
1521        )

Deserialize results of searched Destiny2 entities.

Parameters
Returns
def deserialize_inventory_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.InventoryEntity:
1550    def deserialize_inventory_entity(  # noqa: C901 Too complex.
1551        self, payload: typedefs.JSONObject, /
1552    ) -> entity.InventoryEntity:
1553
1554        props = self._set_entity_attrs(payload)
1555        objects = self._deserialize_inventory_item_objects(payload)
1556
1557        collectible_hash: typing.Optional[int] = None
1558        if raw_collectible_hash := payload.get("collectibleHash"):
1559            collectible_hash = int(raw_collectible_hash)
1560
1561        secondary_icon: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1562        if raw_second_icon := payload.get("secondaryIcon"):
1563            secondary_icon = assets.Image(raw_second_icon)
1564
1565        secondary_overlay: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1566        if raw_second_overlay := payload.get("secondaryOverlay"):
1567            secondary_overlay = assets.Image(raw_second_overlay)
1568
1569        secondary_special: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1570        if raw_second_special := payload.get("secondarySpecial"):
1571            secondary_special = assets.Image(raw_second_special)
1572
1573        screenshot: undefined.UndefinedOr[assets.Image] = undefined.Undefined
1574        if raw_screenshot := payload.get("screenshot"):
1575            screenshot = assets.Image(raw_screenshot)
1576
1577        watermark_icon: typing.Optional[assets.Image] = None
1578        if raw_watermark_icon := payload.get("iconWatermark"):
1579            watermark_icon = assets.Image(raw_watermark_icon)
1580
1581        watermark_shelved: typing.Optional[assets.Image] = None
1582        if raw_watermark_shelved := payload.get("iconWatermarkShelved"):
1583            watermark_shelved = assets.Image(raw_watermark_shelved)
1584
1585        about: undefined.UndefinedOr[str] = undefined.Undefined
1586        if (raw_about := payload.get("flavorText")) and not typedefs.is_unknown(
1587            raw_about
1588        ):
1589            about = raw_about
1590
1591        ui_item_style: undefined.UndefinedOr[str] = undefined.Undefined
1592        if (
1593            raw_ui_style := payload.get("uiItemDisplayStyle")
1594        ) and not typedefs.is_unknown(raw_ui_style):
1595            ui_item_style = raw_ui_style
1596
1597        tier_and_name: undefined.UndefinedOr[str] = undefined.Undefined
1598        if (
1599            raw_tier_and_name := payload.get("itemTypeAndTierDisplayName")
1600        ) and not typedefs.is_unknown(raw_tier_and_name):
1601            tier_and_name = raw_tier_and_name
1602
1603        type_name: undefined.UndefinedOr[str] = undefined.Undefined
1604        if (
1605            raw_type_name := payload.get("itemTypeDisplayName")
1606        ) and not typedefs.is_unknown(raw_type_name):
1607            type_name = raw_type_name
1608
1609        display_source: undefined.UndefinedOr[str] = undefined.Undefined
1610        if (
1611            raw_display_source := payload.get("displaySource")
1612        ) and not typedefs.is_unknown(raw_display_source):
1613            display_source = raw_display_source
1614
1615        lorehash: typing.Optional[int] = None
1616        if raw_lore_hash := payload.get("loreHash"):
1617            lorehash = int(raw_lore_hash)
1618
1619        summary_hash: typing.Optional[int] = None
1620        if raw_summary_hash := payload.get("summaryItemHash"):
1621            summary_hash = raw_summary_hash
1622
1623        breaker_type_hash: typing.Optional[int] = None
1624        if raw_breaker_type_hash := payload.get("breakerTypeHash"):
1625            breaker_type_hash = int(raw_breaker_type_hash)
1626
1627        damage_types: typing.Optional[collections.Sequence[int]] = None
1628        if raw_damage_types := payload.get("damageTypes"):
1629            damage_types = [int(type_) for type_ in raw_damage_types]
1630
1631        damagetype_hashes: typing.Optional[collections.Sequence[int]] = None
1632        if raw_damagetype_hashes := payload.get("damageTypeHashes"):
1633            damagetype_hashes = [int(type_) for type_ in raw_damagetype_hashes]
1634
1635        default_damagetype_hash: typing.Optional[int] = None
1636        if raw_defaultdmg_hash := payload.get("defaultDamageTypeHash"):
1637            default_damagetype_hash = int(raw_defaultdmg_hash)
1638
1639        emblem_objective_hash: typing.Optional[int] = None
1640        if raw_emblem_obj_hash := payload.get("emblemObjectiveHash"):
1641            emblem_objective_hash = int(raw_emblem_obj_hash)
1642
1643        tier_type: typing.Optional[enums.TierType] = None
1644        tier: typing.Optional[enums.ItemTier] = None
1645        bucket_hash: typing.Optional[int] = None
1646        recovery_hash: typing.Optional[int] = None
1647        tier_name: undefined.UndefinedOr[str] = undefined.Undefined
1648        isinstance_item: bool = False
1649        expire_tool_tip: undefined.UndefinedOr[str] = undefined.Undefined
1650        expire_in_orbit_message: undefined.UndefinedOr[str] = undefined.Undefined
1651        suppress_expiration: bool = False
1652        max_stack_size: typing.Optional[int] = None
1653        stack_label: undefined.UndefinedOr[str] = undefined.Undefined
1654
1655        if inventory := payload.get("inventory"):
1656            tier_type = enums.TierType(int(inventory["tierType"]))
1657            tier = enums.ItemTier(int(inventory["tierTypeHash"]))
1658            bucket_hash = int(inventory["bucketTypeHash"])
1659            recovery_hash = int(inventory["recoveryBucketTypeHash"])
1660            tier_name = inventory["tierTypeName"]
1661            isinstance_item = inventory["isInstanceItem"]
1662            suppress_expiration = inventory["suppressExpirationWhenObjectivesComplete"]
1663            max_stack_size = int(inventory["maxStackSize"])
1664
1665            try:
1666                stack_label = inventory["stackUniqueLabel"]
1667            except KeyError:
1668                pass
1669
1670        return entity.InventoryEntity(
1671            net=self._net,
1672            collectible_hash=collectible_hash,
1673            name=props.name,
1674            about=about,
1675            emblem_objective_hash=emblem_objective_hash,
1676            suppress_expiration=suppress_expiration,
1677            max_stack_size=max_stack_size,
1678            stack_label=stack_label,
1679            tier=tier,
1680            tier_type=tier_type,
1681            tier_name=tier_name,
1682            bucket_hash=bucket_hash,
1683            recovery_bucket_hash=recovery_hash,
1684            isinstance_item=isinstance_item,
1685            expire_in_orbit_message=expire_in_orbit_message,
1686            expiration_tooltip=expire_tool_tip,
1687            lore_hash=lorehash,
1688            type_and_tier_name=tier_and_name,
1689            summary_hash=summary_hash,
1690            ui_display_style=ui_item_style,
1691            type_name=type_name,
1692            breaker_type_hash=breaker_type_hash,
1693            description=props.description,
1694            display_source=display_source,
1695            hash=props.hash,
1696            damage_types=damage_types,
1697            index=props.index,
1698            icon=props.icon,
1699            has_icon=props.has_icon,
1700            screenshot=screenshot,
1701            watermark_icon=watermark_icon,
1702            watermark_shelved=watermark_shelved,
1703            secondary_icon=secondary_icon,
1704            secondary_overlay=secondary_overlay,
1705            secondary_special=secondary_special,
1706            type=enums.ItemType(int(payload["itemType"])),
1707            trait_hashes=[int(id_) for id_ in payload.get("traitHashes", [])],
1708            trait_ids=[trait for trait in payload.get("traitIds", [])],
1709            category_hashes=[int(hash_) for hash_ in payload["itemCategoryHashes"]],
1710            item_class=enums.Class(int(payload["classType"])),
1711            sub_type=enums.ItemSubType(int(payload["itemSubType"])),
1712            breaker_type=int(payload["breakerType"]),
1713            default_damagetype=int(payload["defaultDamageType"]),
1714            default_damagetype_hash=default_damagetype_hash,
1715            damagetype_hashes=damagetype_hashes,
1716            tooltip_notifications=payload["tooltipNotifications"],
1717            not_transferable=payload["nonTransferrable"],
1718            allow_actions=payload["allowActions"],
1719            is_equippable=payload["equippable"],
1720            objects=objects,
1721            background_colors=payload.get("backgroundColor", {}),
1722            season_hash=payload.get("seasonHash"),
1723            has_postmaster_effect=payload["doesPostmasterPullHaveSideEffects"],
1724        )

Deserialize a JSON payload of an inventory entity item information.

This can be any item from DestinyInventoryItemDefinition definition.

Parameters
Returns
def deserialize_objective_entity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.entity.ObjectiveEntity:
1726    def deserialize_objective_entity(
1727        self, payload: typedefs.JSONObject, /
1728    ) -> entity.ObjectiveEntity:
1729        props = self._set_entity_attrs(payload)
1730        return entity.ObjectiveEntity(
1731            net=self._net,
1732            hash=props.hash,
1733            index=props.index,
1734            description=props.description,
1735            name=props.name,
1736            has_icon=props.has_icon,
1737            icon=props.icon,
1738            unlock_value_hash=payload["unlockValueHash"],
1739            completion_value=payload["completionValue"],
1740            scope=entity.GatingScope(int(payload["scope"])),
1741            location_hash=payload["locationHash"],
1742            allowed_negative_value=payload["allowNegativeValue"],
1743            allowed_value_change=payload["allowValueChangeWhenCompleted"],
1744            counting_downward=payload["isCountingDownward"],
1745            value_style=entity.ValueUIStyle(int(payload["valueStyle"])),
1746            progress_description=payload["progressDescription"],
1747            perks=payload["perks"],
1748            stats=payload["stats"],
1749            minimum_visibility=payload["minimumVisibilityThreshold"],
1750            allow_over_completion=payload["allowOvercompletion"],
1751            show_value_style=payload["showValueOnComplete"],
1752            display_only_objective=payload["isDisplayOnlyObjective"],
1753            complete_value_style=entity.ValueUIStyle(
1754                int(payload["completedValueStyle"])
1755            ),
1756            progress_value_style=entity.ValueUIStyle(
1757                int(payload["inProgressValueStyle"])
1758            ),
1759            ui_label=payload["uiLabel"],
1760            ui_style=entity.ObjectiveUIStyle(int(payload["uiStyle"])),
1761        )

Deserialize a JSON payload of an objective entity information.

Parameters
Returns
def deserialize_activity( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.Activity:
1789    def deserialize_activity(
1790        self,
1791        payload: typedefs.JSONObject,
1792        /,
1793    ) -> activity.Activity:
1794        period = time.clean_date(payload["period"])
1795        details = payload["activityDetails"]
1796        ref_id = int(details["referenceId"])
1797        instance_id = int(details["instanceId"])
1798        mode = enums.GameMode(details["mode"])
1799        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1800        is_private = details["isPrivate"]
1801        membership_type = enums.MembershipType(int(details["membershipType"]))
1802
1803        # Since we're using the same fields for post activity method
1804        # this check is required since post activity doesn't values values
1805        values = self._deserialize_activity_values(payload["values"])
1806
1807        return activity.Activity(
1808            net=self._net,
1809            hash=ref_id,
1810            instance_id=instance_id,
1811            mode=mode,
1812            modes=modes,
1813            is_private=is_private,
1814            membership_type=membership_type,
1815            occurred_at=period,
1816            values=values,
1817        )

Deserialize a JSON payload of an activity history information.

Parameters
Returns
def deserialize_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.Activity]:
1819    def deserialize_activities(
1820        self, payload: typedefs.JSONObject
1821    ) -> iterators.FlatIterator[activity.Activity]:
1822        return iterators.FlatIterator(
1823            [
1824                self.deserialize_activity(activity_)
1825                for activity_ in payload["activities"]
1826            ]
1827        )

Deserialize a JSON payload of an array of activity history information.

Parameters
Returns
  • aiobungie.iterators.FlatIterator[aiobungie.crates.Activity]: Am iterator over activity objects of the deserialized payload.
def deserialize_extended_weapon_values( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.ExtendedWeaponValues:
1829    def deserialize_extended_weapon_values(
1830        self, payload: typedefs.JSONObject
1831    ) -> activity.ExtendedWeaponValues:
1832
1833        assists: typing.Optional[int] = None
1834        if raw_assists := payload["values"].get("uniqueWeaponAssists"):
1835            assists = raw_assists["basic"]["value"]
1836        assists_damage: typing.Optional[int] = None
1837
1838        if raw_assists_damage := payload["values"].get("uniqueWeaponAssistDamage"):
1839            assists_damage = raw_assists_damage["basic"]["value"]
1840
1841        return activity.ExtendedWeaponValues(
1842            reference_id=int(payload["referenceId"]),
1843            kills=payload["values"]["uniqueWeaponKills"]["basic"]["value"],
1844            precision_kills=payload["values"]["uniqueWeaponPrecisionKills"]["basic"][
1845                "value"
1846            ],
1847            assists=assists,
1848            assists_damage=assists_damage,
1849            precision_kills_percentage=(
1850                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"]["value"],
1851                payload["values"]["uniqueWeaponKillsPrecisionKills"]["basic"][
1852                    "displayValue"
1853                ],
1854            ),
1855        )

Deserialize values of extended weapons JSON object.

Parameters
Returns
def deserialize_post_activity_player( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.activity.PostActivityPlayer:
1878    def deserialize_post_activity_player(
1879        self, payload: typedefs.JSONObject, /
1880    ) -> activity.PostActivityPlayer:
1881        player = payload["player"]
1882
1883        class_hash: typedefs.NoneOr[int] = None
1884        if (class_hash := player.get("classHash")) is not None:
1885            class_hash = class_hash
1886
1887        race_hash: typedefs.NoneOr[int] = None
1888        if (race_hash := player.get("raceHash")) is not None:
1889            race_hash = race_hash
1890
1891        gender_hash: typedefs.NoneOr[int] = None
1892        if (gender_hash := player.get("genderHash")) is not None:
1893            gender_hash = gender_hash
1894
1895        character_class: undefined.UndefinedOr[str] = undefined.Undefined
1896        if (
1897            character_class := player.get("characterClass")
1898        ) and not typedefs.is_unknown(character_class):
1899            character_class = character_class
1900
1901        character_level: typedefs.NoneOr[int] = None
1902        if (character_level := player.get("characterLevel")) is not None:
1903            character_level = character_level
1904
1905        return activity.PostActivityPlayer(
1906            standing=int(payload["standing"]),
1907            score=int(payload["score"]["basic"]["value"]),
1908            character_id=payload["characterId"],
1909            destiny_user=self.deserialize_destiny_membership(
1910                player["destinyUserInfo"]
1911            ),
1912            character_class=character_class,
1913            character_level=character_level,
1914            race_hash=race_hash,
1915            gender_hash=gender_hash,
1916            class_hash=class_hash,
1917            light_level=int(player["lightLevel"]),
1918            emblem_hash=int(player["emblemHash"]),
1919            values=self._deserialize_activity_values(payload["values"]),
1920            extended_values=self._deserialize_extended_values(payload["extended"]),
1921        )

Deserialize a JSON payload of a post activity player information.

Parameters
Returns
def deserialize_post_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.PostActivity:
1933    def deserialize_post_activity(
1934        self, payload: typedefs.JSONObject
1935    ) -> activity.PostActivity:
1936        period = time.clean_date(payload["period"])
1937        details = payload["activityDetails"]
1938        ref_id = int(details["referenceId"])
1939        instance_id = int(details["instanceId"])
1940        mode = enums.GameMode(details["mode"])
1941        modes = [enums.GameMode(int(mode_)) for mode_ in details["modes"]]
1942        is_private = details["isPrivate"]
1943        membership_type = enums.MembershipType(int(details["membershipType"]))
1944        return activity.PostActivity(
1945            net=self._net,
1946            hash=ref_id,
1947            membership_type=membership_type,
1948            instance_id=instance_id,
1949            mode=mode,
1950            modes=modes,
1951            is_private=is_private,
1952            occurred_at=period,
1953            starting_phase=int(payload["startingPhaseIndex"]),
1954            players=[
1955                self.deserialize_post_activity_player(player)
1956                for player in payload["entries"]
1957            ],
1958            teams=[
1959                self._deserialize_post_activity_team(team) for team in payload["teams"]
1960            ],
1961        )

Deserialize a JSON payload of a post activity information.

Parameters
Returns
def deserialize_aggregated_activity( self, payload: dict[str, typing.Any]) -> aiobungie.crates.activity.AggregatedActivity:
1999    def deserialize_aggregated_activity(
2000        self, payload: typedefs.JSONObject
2001    ) -> activity.AggregatedActivity:
2002        return activity.AggregatedActivity(
2003            hash=int(payload["activityHash"]),
2004            values=self._deserialize_aggregated_activity_values(payload["values"]),
2005        )

Deserialize a JSON payload of an aggregated activity.

Parameters
Returns
def deserialize_aggregated_activities( self, payload: dict[str, typing.Any]) -> aiobungie.FlatIterator[aiobungie.crates.activity.AggregatedActivity]:
2007    def deserialize_aggregated_activities(
2008        self, payload: typedefs.JSONObject
2009    ) -> iterators.FlatIterator[activity.AggregatedActivity]:
2010        return iterators.FlatIterator(
2011            [
2012                self.deserialize_aggregated_activity(activity)
2013                for activity in payload["activities"]
2014            ]
2015        )

Deserialize a JSON payload of an array of aggregated activities.

Parameters
Returns
def deserialize_linked_profiles( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.LinkedProfile:
2017    def deserialize_linked_profiles(
2018        self, payload: typedefs.JSONObject
2019    ) -> profile.LinkedProfile:
2020        bungie_user = self.deserialize_partial_bungie_user(payload["bnetMembership"])
2021        error_profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2022        profiles_vec: typing.MutableSequence[user.DestinyMembership] = []
2023
2024        if raw_profile := payload.get("profiles"):
2025            for pfile in raw_profile:
2026                profiles_vec.append(self.deserialize_destiny_membership(pfile))
2027
2028        if raw_profiles_with_errors := payload.get("profilesWithErrors"):
2029            for raw_error_pfile in raw_profiles_with_errors:
2030                if error_pfile := raw_error_pfile.get("infoCard"):
2031                    error_profiles_vec.append(
2032                        self.deserialize_destiny_membership(error_pfile)
2033                    )
2034
2035        return profile.LinkedProfile(
2036            net=self._net,
2037            bungie=bungie_user,
2038            profiles=profiles_vec,
2039            profiles_with_errors=error_profiles_vec,
2040        )

Deserialize a JSON payload of Bungie.net hard linked profile information.

Parameters
Returns
def deserialize_clan_banners( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.clans.ClanBanner]:
2042    def deserialize_clan_banners(
2043        self, payload: typedefs.JSONObject
2044    ) -> collections.Sequence[clans.ClanBanner]:
2045        banners_seq: typing.MutableSequence[clans.ClanBanner] = []
2046        if banners := payload.get("clanBannerDecals"):
2047            for k, v in banners.items():
2048                banner_obj = clans.ClanBanner(
2049                    id=int(k),
2050                    foreground=assets.Image(v["foregroundPath"]),
2051                    background=assets.Image(v["backgroundPath"]),
2052                )
2053                banners_seq.append(banner_obj)
2054        return banners_seq

Deserialize a JSON array of a clan banners information.

Parameters
Returns
def deserialize_public_milestone_content( self, payload: dict[str, typing.Any]) -> aiobungie.crates.milestones.MilestoneContent:
2056    def deserialize_public_milestone_content(
2057        self, payload: typedefs.JSONObject
2058    ) -> milestones.MilestoneContent:
2059        items_categoris: typedefs.NoneOr[milestones.MilestoneItems] = None
2060        if raw_categories := payload.get("itemCategories"):
2061            for item in raw_categories:
2062                title = undefined.Undefined
2063                if raw_title := item.get("title"):
2064                    if raw_title != typedefs.Unknown:
2065                        title = raw_title
2066                if raw_hashes := item.get("itemHashes"):
2067                    hashes: collections.Sequence[int] = raw_hashes
2068
2069                items_categoris = milestones.MilestoneItems(title=title, hashes=hashes)
2070
2071        about = undefined.Undefined
2072        if (raw_about := payload["about"]) != typedefs.Unknown:
2073            about = raw_about
2074
2075        status = undefined.Undefined
2076        if (raw_status := payload["status"]) != typedefs.Unknown:
2077            status = raw_status
2078
2079        tips: typing.MutableSequence[undefined.UndefinedOr[str]] = []
2080        if raw_tips := payload.get("tips"):
2081            for raw_tip in raw_tips:
2082                if raw_tip == typedefs.Unknown:
2083                    raw_tip = undefined.Undefined
2084                tips.append(raw_tip)
2085
2086        return milestones.MilestoneContent(
2087            about=about, status=status, tips=tips, items=items_categoris
2088        )

Deserialize a JSON payload of milestone content information.

Parameters
Returns
def deserialize_friend( self, payload: dict[str, typing.Any], /) -> aiobungie.crates.friends.Friend:
2090    def deserialize_friend(self, payload: typedefs.JSONObject, /) -> friends.Friend:
2091        name = undefined.Undefined
2092        if (raw_name := payload["bungieGlobalDisplayName"]) != typedefs.Unknown:
2093            name = raw_name
2094
2095        bungie_user: typedefs.NoneOr[user.BungieUser] = None
2096
2097        if raw_bungie_user := payload.get("bungieNetUser"):
2098            bungie_user = self.deserialize_bungie_user(raw_bungie_user)
2099
2100        return friends.Friend(
2101            net=self._net,
2102            id=int(payload["lastSeenAsMembershipId"]),
2103            name=name,
2104            code=payload.get("bungieGlobalDisplayNameCode"),
2105            relationship=enums.Relationship(payload["relationship"]),
2106            user=bungie_user,
2107            online_status=enums.Presence(payload["onlineStatus"]),
2108            online_title=payload["onlineTitle"],
2109            type=enums.MembershipType(payload["lastSeenAsBungieMembershipType"]),
2110        )

Deserialize a JSON payload of a Bungie friend information.

Parameters
Returns
def deserialize_friends( self, payload: dict[str, typing.Any]) -> collections.abc.Sequence[aiobungie.crates.friends.Friend]:
2112    def deserialize_friends(
2113        self, payload: typedefs.JSONObject
2114    ) -> collections.Sequence[friends.Friend]:
2115        mut_seq: typing.MutableSequence[friends.Friend] = []
2116        if raw_friends := payload.get("friends"):
2117            for friend in raw_friends:
2118                mut_seq.append(self.deserialize_friend(friend))
2119        return mut_seq

Deserialize a JSON sequence of Bungie friends information.

This is usually used to deserialize the incoming/outgoing friend requests.

Parameters
Returns
def deserialize_friend_requests( self, payload: dict[str, typing.Any]) -> aiobungie.crates.friends.FriendRequestView:
2121    def deserialize_friend_requests(
2122        self, payload: typedefs.JSONObject
2123    ) -> friends.FriendRequestView:
2124        incoming: typing.MutableSequence[friends.Friend] = []
2125        outgoing: typing.MutableSequence[friends.Friend] = []
2126
2127        if raw_incoming_requests := payload.get("incomingRequests"):
2128            for incoming_request in raw_incoming_requests:
2129                incoming.append(self.deserialize_friend(incoming_request))
2130
2131        if raw_outgoing_requests := payload.get("outgoingRequests"):
2132            for outgoing_request in raw_outgoing_requests:
2133                outgoing.append(self.deserialize_friend(outgoing_request))
2134
2135        return friends.FriendRequestView(incoming=incoming, outgoing=outgoing)

Deserialize a JSON sequence of Bungie friend requests information.

This is used for incoming/outgoing friend requests.

Parameters
Returns
def deserialize_fireteams( self, payload: dict[str, typing.Any]) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.Fireteam]]:
2160    def deserialize_fireteams(
2161        self, payload: typedefs.JSONObject
2162    ) -> typedefs.NoneOr[collections.Sequence[fireteams.Fireteam]]:
2163        fireteams_: typing.MutableSequence[fireteams.Fireteam] = []
2164
2165        result: list[typedefs.JSONObject]
2166        if not (result := payload["results"]):
2167            return None
2168        for elem in result:
2169            fireteams_.append(
2170                self._set_fireteam_fields(
2171                    elem, total_results=int(payload["totalResults"])
2172                )
2173            )
2174        return fireteams_

Deserialize a JSON sequence of Bungie fireteams information.

Parameters
Returns
def deserialize_fireteam_destiny_users( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamUser:
2176    def deserialize_fireteam_destiny_users(
2177        self, payload: typedefs.JSONObject
2178    ) -> fireteams.FireteamUser:
2179        destiny_obj = self.deserialize_destiny_membership(payload)
2180        # We could helpers.just return a DestinyMembership object but this is
2181        # missing the fireteam display name and id fields.
2182        return fireteams.FireteamUser(
2183            net=self._net,
2184            id=destiny_obj.id,
2185            code=destiny_obj.code,
2186            icon=destiny_obj.icon,
2187            types=destiny_obj.types,
2188            type=destiny_obj.type,
2189            is_public=destiny_obj.is_public,
2190            crossave_override=destiny_obj.crossave_override,
2191            name=destiny_obj.name,
2192            last_seen_name=destiny_obj.last_seen_name,
2193            fireteam_display_name=payload["FireteamDisplayName"],
2194            fireteam_membership_id=enums.MembershipType(
2195                payload["FireteamMembershipType"]
2196            ),
2197        )

Deserialize a JSON payload of Bungie fireteam destiny users information.

Parameters
Returns
def deserialize_fireteam_members( self, payload: dict[str, typing.Any], *, alternatives: bool = False) -> Optional[collections.abc.Sequence[aiobungie.crates.fireteams.FireteamMember]]:
2199    def deserialize_fireteam_members(
2200        self, payload: typedefs.JSONObject, *, alternatives: bool = False
2201    ) -> typing.Optional[collections.Sequence[fireteams.FireteamMember]]:
2202        members_: list[fireteams.FireteamMember] = []
2203        if members := payload.get("Members" if not alternatives else "Alternates"):
2204            for member in members:
2205                bungie_fields = self.deserialize_partial_bungie_user(member)
2206                members_fields = fireteams.FireteamMember(
2207                    destiny_user=self.deserialize_fireteam_destiny_users(member),
2208                    has_microphone=member["hasMicrophone"],
2209                    character_id=int(member["characterId"]),
2210                    date_joined=time.clean_date(member["dateJoined"]),
2211                    last_platform_invite_date=time.clean_date(
2212                        member["lastPlatformInviteAttemptDate"]
2213                    ),
2214                    last_platform_invite_result=int(
2215                        member["lastPlatformInviteAttemptResult"]
2216                    ),
2217                    net=self._net,
2218                    name=bungie_fields.name,
2219                    id=bungie_fields.id,
2220                    icon=bungie_fields.icon,
2221                    is_public=bungie_fields.is_public,
2222                    crossave_override=bungie_fields.crossave_override,
2223                    types=bungie_fields.types,
2224                    type=bungie_fields.type,
2225                )
2226                members_.append(members_fields)
2227        else:
2228            return None
2229        return members_

Deserialize a JSON sequence of Bungie fireteam members information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • alternatives (bool): If set to True, Then it will deserialize the alternatives data in the payload. If not the it will just deserialize the members data.
Returns
def deserialize_available_fireteams( self, data: dict[str, typing.Any], *, no_results: bool = False) -> Union[aiobungie.crates.fireteams.AvailableFireteam, collections.abc.Sequence[aiobungie.crates.fireteams.AvailableFireteam]]:
2231    def deserialize_available_fireteams(
2232        self,
2233        data: typedefs.JSONObject,
2234        *,
2235        no_results: bool = False,
2236    ) -> typing.Union[
2237        fireteams.AvailableFireteam, collections.Sequence[fireteams.AvailableFireteam]
2238    ]:
2239        fireteams_: list[fireteams.AvailableFireteam] = []
2240
2241        # This needs to be used outside the results
2242        # JSON key.
2243        if no_results is True:
2244            payload = data
2245
2246        if result := payload.get("results"):
2247
2248            for fireteam in result:
2249                found_fireteams = self._set_fireteam_fields(fireteam["Summary"])
2250                fireteams_fields = fireteams.AvailableFireteam(
2251                    id=found_fireteams.id,
2252                    group_id=found_fireteams.group_id,
2253                    platform=found_fireteams.platform,
2254                    activity_type=found_fireteams.activity_type,
2255                    is_immediate=found_fireteams.is_immediate,
2256                    is_public=found_fireteams.is_public,
2257                    is_valid=found_fireteams.is_valid,
2258                    owner_id=found_fireteams.owner_id,
2259                    player_slot_count=found_fireteams.player_slot_count,
2260                    available_player_slots=found_fireteams.available_player_slots,
2261                    available_alternate_slots=found_fireteams.available_alternate_slots,
2262                    title=found_fireteams.title,
2263                    date_created=found_fireteams.date_created,
2264                    locale=found_fireteams.locale,
2265                    last_modified=found_fireteams.last_modified,
2266                    total_results=found_fireteams.total_results,
2267                    members=self.deserialize_fireteam_members(payload),
2268                    alternatives=self.deserialize_fireteam_members(
2269                        payload, alternatives=True
2270                    ),
2271                )
2272            fireteams_.append(fireteams_fields)
2273            if no_results:
2274                return fireteams_fields
2275        return fireteams_

Deserialize a JSON payload of a sequence of/fireteam information.

Parameters
  • payload (aiobungie.typedefs.JSONObject): The JSON payload.
  • no_results (bool): Whether to deserialize the data from results in the payload or not.
Returns
  • typing.Union[aiobungie.crates.fireteams.AvailableFireteam, collections.Sequence[aiobungie.crates.fireteams.AvailableFireteam]] # noqa (E501): An available fireteam or a sequence of available fireteam.
def deserialize_fireteam_party( self, payload: dict[str, typing.Any]) -> aiobungie.crates.fireteams.FireteamParty:
2277    def deserialize_fireteam_party(
2278        self, payload: typedefs.JSONObject
2279    ) -> fireteams.FireteamParty:
2280        last_destination_hash: typing.Optional[int] = None
2281        if raw_dest_hash := payload.get("lastOrbitedDestinationHash"):
2282            last_destination_hash = int(raw_dest_hash)
2283
2284        return fireteams.FireteamParty(
2285            members=[
2286                self._deserialize_fireteam_party_member(member)
2287                for member in payload["partyMembers"]
2288            ],
2289            activity=self._deserialize_fireteam_party_current_activity(
2290                payload["currentActivity"]
2291            ),
2292            settings=self._deserialize_fireteam_party_settings(payload["joinability"]),
2293            last_destination_hash=last_destination_hash,
2294            tracking=payload["tracking"],
2295        )

Deserialize a JSON payload of profileTransitory component response.

Parameters
Returns
def deserialize_seasonal_artifact(self, payload: dict[str, typing.Any]) -> aiobungie.crates.season.Artifact:
2342    def deserialize_seasonal_artifact(
2343        self, payload: typedefs.JSONObject
2344    ) -> season.Artifact:
2345        if raw_artifact := payload.get("seasonalArtifact"):
2346            if points := raw_artifact.get("pointProgression"):
2347                points_prog = progressions.Progression(
2348                    hash=points["progressionHash"],
2349                    level=points["level"],
2350                    cap=points["levelCap"],
2351                    daily_limit=points["dailyLimit"],
2352                    weekly_limit=points["weeklyLimit"],
2353                    current_progress=points["currentProgress"],
2354                    daily_progress=points["dailyProgress"],
2355                    needed=points["progressToNextLevel"],
2356                    next_level=points["nextLevelAt"],
2357                )
2358
2359            if bonus := raw_artifact.get("powerBonusProgression"):
2360                power_bonus_prog = progressions.Progression(
2361                    hash=bonus["progressionHash"],
2362                    level=bonus["level"],
2363                    cap=bonus["levelCap"],
2364                    daily_limit=bonus["dailyLimit"],
2365                    weekly_limit=bonus["weeklyLimit"],
2366                    current_progress=bonus["currentProgress"],
2367                    daily_progress=bonus["dailyProgress"],
2368                    needed=bonus["progressToNextLevel"],
2369                    next_level=bonus["nextLevelAt"],
2370                )
2371            artifact = season.Artifact(
2372                net=self._net,
2373                hash=raw_artifact["artifactHash"],
2374                power_bonus=raw_artifact["powerBonus"],
2375                acquired_points=raw_artifact["pointsAcquired"],
2376                bonus=power_bonus_prog,
2377                points=points_prog,
2378            )
2379        return artifact

Deserialize a JSON payload of a Destiny 2 seasonal artifact information.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_profile_progression( self, payload: dict[str, typing.Any]) -> aiobungie.crates.profile.ProfileProgression:
2381    def deserialize_profile_progression(
2382        self, payload: typedefs.JSONObject
2383    ) -> profile.ProfileProgression:
2384        return profile.ProfileProgression(
2385            artifact=self.deserialize_seasonal_artifact(payload["data"]),
2386            checklist={
2387                int(check_id): checklists
2388                for check_id, checklists in payload["data"]["checklists"].items()
2389            },
2390        )

Deserialize a JSON payload of a profile progression component.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_instanced_item( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemInstance:
2392    def deserialize_instanced_item(
2393        self, payload: typedefs.JSONObject
2394    ) -> items.ItemInstance:
2395        damage_type_hash: typing.Optional[int] = None
2396        if raw_damagetype_hash := payload.get("damageTypeHash"):
2397            damage_type_hash = int(raw_damagetype_hash)
2398
2399        required_hashes: typing.Optional[collections.Collection[int]] = None
2400        if raw_required_hashes := payload.get("unlockHashesRequiredToEquip"):
2401            required_hashes = [int(raw_hash) for raw_hash in raw_required_hashes]
2402
2403        breaker_type: typing.Optional[items.ItemBreakerType] = None
2404        if raw_break_type := payload.get("breakerType"):
2405            breaker_type = items.ItemBreakerType(int(raw_break_type))
2406
2407        breaker_type_hash: typing.Optional[int] = None
2408        if raw_break_type_hash := payload.get("breakerTypeHash"):
2409            breaker_type_hash = int(raw_break_type_hash)
2410
2411        energy: typing.Optional[items.ItemEnergy] = None
2412        if raw_energy := payload.get("energy"):
2413            energy = self.deserialize_item_energy(raw_energy)
2414
2415        primary_stats = None
2416        if raw_primary_stats := payload.get("primaryStat"):
2417            primary_stats = self.deserialize_item_stats_view(raw_primary_stats)
2418
2419        return items.ItemInstance(
2420            damage_type=enums.DamageType(int(payload["damageType"])),
2421            damage_type_hash=damage_type_hash,
2422            primary_stat=primary_stats,
2423            item_level=int(payload["itemLevel"]),
2424            quality=int(payload["quality"]),
2425            is_equipped=payload["isEquipped"],
2426            can_equip=payload["canEquip"],
2427            equip_required_level=int(payload["equipRequiredLevel"]),
2428            required_equip_unlock_hashes=required_hashes,
2429            cant_equip_reason=int(payload["cannotEquipReason"]),
2430            breaker_type=breaker_type,
2431            breaker_type_hash=breaker_type_hash,
2432            energy=energy,
2433        )

Deserialize a JSON object into an instanced item.

Parameters
  • payload (aiobungie.internal.helpers.JsonObject): The JSON payload.
Returns
def deserialize_item_energy( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemEnergy:
2435    def deserialize_item_energy(self, payload: typedefs.JSONObject) -> items.ItemEnergy:
2436        energy_hash: typing.Optional[int] = None
2437        if raw_energy_hash := payload.get("energyTypeHash"):
2438            energy_hash = int(raw_energy_hash)
2439
2440        return items.ItemEnergy(
2441            hash=energy_hash,
2442            type=items.ItemEnergyType(int(payload["energyType"])),
2443            capacity=int(payload["energyCapacity"]),
2444            used_energy=int(payload["energyUsed"]),
2445            unused_energy=int(payload["energyUnused"]),
2446        )
def deserialize_item_perk(self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemPerk:
2448    def deserialize_item_perk(self, payload: typedefs.JSONObject) -> items.ItemPerk:
2449        perk_hash: typing.Optional[int] = None
2450        if raw_perk_hash := payload.get("perkHash"):
2451            perk_hash = int(raw_perk_hash)
2452
2453        return items.ItemPerk(
2454            hash=perk_hash,
2455            icon=assets.Image(payload["iconPath"]),
2456            is_active=payload["isActive"],
2457            is_visible=payload["visible"],
2458        )
def deserialize_item_socket( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemSocket:
2460    def deserialize_item_socket(self, payload: typedefs.JSONObject) -> items.ItemSocket:
2461        plug_hash: typing.Optional[int] = None
2462        if raw_plug_hash := payload.get("plugHash"):
2463            plug_hash = int(raw_plug_hash)
2464
2465        enable_fail_indexes: typing.Optional[list[int]] = None
2466        if raw_indexes := payload.get("enableFailIndexes"):
2467            enable_fail_indexes = [int(index) for index in raw_indexes]
2468
2469        return items.ItemSocket(
2470            plug_hash=plug_hash,
2471            is_enabled=payload["isEnabled"],
2472            enable_fail_indexes=enable_fail_indexes,
2473            is_visible=payload.get("visible"),
2474        )
def deserialize_item_stats_view( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.ItemStatsView:
2476    def deserialize_item_stats_view(
2477        self, payload: typedefs.JSONObject
2478    ) -> items.ItemStatsView:
2479        return items.ItemStatsView(
2480            stat_hash=payload.get("statHash"), value=payload.get("value")
2481        )
def deserialize_plug_item_state( self, payload: dict[str, typing.Any]) -> aiobungie.crates.items.PlugItemState:
2483    def deserialize_plug_item_state(
2484        self, payload: typedefs.JSONObject
2485    ) -> items.PlugItemState:
2486        item_hash: typing.Optional[int] = None
2487        if raw_item_hash := payload.get("plugItemHash"):
2488            item_hash = int(raw_item_hash)
2489
2490        insert_fail_indexes: typedefs.NoneOr[list[int]] = None
2491        if raw_fail_indexes := payload.get("insertFailIndexes"):
2492            insert_fail_indexes = [int(k) for k in raw_fail_indexes]
2493
2494        enable_fail_indexes: typedefs.NoneOr[list[int]] = None
2495        if raw_enabled_indexes := payload.get("enableFailIndexes"):
2496            enable_fail_indexes = [int(k) for k in raw_enabled_indexes]
2497
2498        return items.PlugItemState(
2499            item_hash=item_hash,
2500            insert_fail_indexes=insert_fail_indexes,
2501            enable_fail_indexes=enable_fail_indexes,
2502            is_enabled=payload["enabled"],
2503            can_insert=payload["canInsert"],
2504        )
@typing.final
class FireteamActivity(builtins.int, aiobungie.Enum):
 68@typing.final
 69class FireteamActivity(int, enums.Enum):
 70    """An enum for the fireteam activities."""
 71
 72    ALL = 0
 73    CRUCIBLE = 2
 74    TRIALS_OF_OSIRIS = 3
 75    NIGHTFALL = 4
 76    ANY = 5
 77    GAMBIT = 6
 78    BLIND_WELL = 7
 79    NIGHTMARE_HUNTS = 12
 80    ALTARS_OF_SORROWS = 14
 81    DUNGEON = 15
 82    RAID_LW = 20
 83    RAID_GOS = 21
 84    RAID_DSC = 22
 85    EXO_CHALLENGE = 23
 86    S12_WRATHBORN = 24
 87    EMPIRE_HUNTS = 25
 88    S13_BATTLEGROUNDS = 26
 89    EXOTIC_QUEST = 27
 90    RAID_VOG = 28
 91    S14_EXPUNGE = 30
 92    S15_ASTRAL_ALIGNMENT = 31
 93    S15_SHATTERED_RELAM = 32
 94    SHATTERED_THRONE = 33
 95    PROPHECY = 34
 96    PIT_OF_HERESY = 35
 97    DOE = 36
 98    """Dares of Eternity."""
 99    DUNGEON_GOA = 37
100    """Grasp of Avarice."""
101    VOW_OF_THE_DISCPILE = 38
102    CAMPAIGN = 39
103    WELLSPRING = 40
104    S16_BATTLEGROUNDS = 41
105    S17_NIGHTMARE_CONTAINMENT = 44
106    S17_SEVER = 45

An enum for the fireteam activities.

CRUCIBLE = <FireteamActivity.CRUCIBLE: 2>
TRIALS_OF_OSIRIS = <FireteamActivity.TRIALS_OF_OSIRIS: 3>
NIGHTFALL = <FireteamActivity.NIGHTFALL: 4>
GAMBIT = <FireteamActivity.GAMBIT: 6>
BLIND_WELL = <FireteamActivity.BLIND_WELL: 7>
NIGHTMARE_HUNTS = <FireteamActivity.NIGHTMARE_HUNTS: 12>
ALTARS_OF_SORROWS = <FireteamActivity.ALTARS_OF_SORROWS: 14>
DUNGEON = <FireteamActivity.DUNGEON: 15>
RAID_LW = <FireteamActivity.RAID_LW: 20>
RAID_GOS = <FireteamActivity.RAID_GOS: 21>
RAID_DSC = <FireteamActivity.RAID_DSC: 22>
EXO_CHALLENGE = <FireteamActivity.EXO_CHALLENGE: 23>
S12_WRATHBORN = <FireteamActivity.S12_WRATHBORN: 24>
EMPIRE_HUNTS = <FireteamActivity.EMPIRE_HUNTS: 25>
S13_BATTLEGROUNDS = <FireteamActivity.S13_BATTLEGROUNDS: 26>
EXOTIC_QUEST = <FireteamActivity.EXOTIC_QUEST: 27>
RAID_VOG = <FireteamActivity.RAID_VOG: 28>
S14_EXPUNGE = <FireteamActivity.S14_EXPUNGE: 30>
S15_ASTRAL_ALIGNMENT = <FireteamActivity.S15_ASTRAL_ALIGNMENT: 31>
S15_SHATTERED_RELAM = <FireteamActivity.S15_SHATTERED_RELAM: 32>
SHATTERED_THRONE = <FireteamActivity.SHATTERED_THRONE: 33>
PROPHECY = <FireteamActivity.PROPHECY: 34>
PIT_OF_HERESY = <FireteamActivity.PIT_OF_HERESY: 35>
DOE = <FireteamActivity.DOE: 36>

Dares of Eternity.

DUNGEON_GOA = <FireteamActivity.DUNGEON_GOA: 37>

Grasp of Avarice.

VOW_OF_THE_DISCPILE = <FireteamActivity.VOW_OF_THE_DISCPILE: 38>
CAMPAIGN = <FireteamActivity.CAMPAIGN: 39>
WELLSPRING = <FireteamActivity.WELLSPRING: 40>
S16_BATTLEGROUNDS = <FireteamActivity.S16_BATTLEGROUNDS: 41>
S17_NIGHTMARE_CONTAINMENT = <FireteamActivity.S17_NIGHTMARE_CONTAINMENT: 44>
S17_SEVER = <FireteamActivity.S17_SEVER: 45>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamDate(builtins.int, aiobungie.Enum):
132@typing.final
133class FireteamDate(int, enums.Enum):
134    """An enum for fireteam date ranges."""
135
136    ALL = 0
137    NOW = 1
138    TODAY = 2
139    TWO_DAYS = 3
140    THIS_WEEK = 4

An enum for fireteam date ranges.

ALL = <FireteamDate.ALL: 0>
NOW = <FireteamDate.NOW: 1>
TODAY = <FireteamDate.TODAY: 2>
TWO_DAYS = <FireteamDate.TWO_DAYS: 3>
THIS_WEEK = <FireteamDate.THIS_WEEK: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class FireteamLanguage(builtins.str, aiobungie.Enum):
109@typing.final
110class FireteamLanguage(str, enums.Enum):
111    """An enum for fireteams languages filters."""
112
113    ALL = ""
114    ENGLISH = "en"
115    FRENCH = "fr"
116    ESPANOL = "es"
117    DEUTSCH = "de"
118    ITALIAN = "it"
119    JAPANESE = "ja"
120    PORTUGUESE = "pt-br"
121    RUSSIAN = "ru"
122    POLISH = "pl"
123    KOREAN = "ko"
124    # ? China
125    ZH_CHT = "zh-cht"
126    ZH_CHS = "zh-chs"
127
128    def __str__(self) -> str:
129        return str(self.value)

An enum for fireteams languages filters.

ENGLISH = <FireteamLanguage.ENGLISH: en>
FRENCH = <FireteamLanguage.FRENCH: fr>
ESPANOL = <FireteamLanguage.ESPANOL: es>
DEUTSCH = <FireteamLanguage.DEUTSCH: de>
ITALIAN = <FireteamLanguage.ITALIAN: it>
JAPANESE = <FireteamLanguage.JAPANESE: ja>
PORTUGUESE = <FireteamLanguage.PORTUGUESE: pt-br>
RUSSIAN = <FireteamLanguage.RUSSIAN: ru>
POLISH = <FireteamLanguage.POLISH: pl>
KOREAN = <FireteamLanguage.KOREAN: ko>
ZH_CHT = <FireteamLanguage.ZH_CHT: zh-cht>
ZH_CHS = <FireteamLanguage.ZH_CHS: zh-chs>
Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@typing.final
class FireteamPlatform(builtins.int, aiobungie.Enum):
55@typing.final
56class FireteamPlatform(int, enums.Enum):
57    """An enum for fireteam related to bungie fireteams.
58    This is different from the normal `aiobungie.MembershipType`.
59    """
60
61    ANY = 0
62    PSN_NETWORK = 1
63    XBOX_LIVE = 2
64    STEAM = 4
65    STADIA = 5

An enum for fireteam related to bungie fireteams. This is different from the normal aiobungie.MembershipType.

PSN_NETWORK = <FireteamPlatform.PSN_NETWORK: 1>
XBOX_LIVE = <FireteamPlatform.XBOX_LIVE: 2>
STEAM = <FireteamPlatform.STEAM: 4>
STADIA = <FireteamPlatform.STADIA: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class Flag(enum.Flag):
102class Flag(__enum.Flag):
103    """Builtin Python enum flag with extra handlings."""
104
105    # Needs to type this here for mypy
106    _value_: int
107
108    @property
109    def name(self) -> str:  # type: ignore[override]
110        if self._name_ is None:
111            self._name_ = f"UNKNOWN {self._value_}"
112
113        return self._name_
114
115    @property
116    def value(self) -> int:  # type: ignore[override]
117        return self._value_
118
119    def __str__(self) -> str:
120        return self.name
121
122    def __repr__(self) -> str:
123        return f"<{type(self).__name__}.{self.name}: {self._value_!s}>"
124
125    def __int__(self) -> int:
126        if isinstance(self.value, _ITERABLE):
127            raise TypeError(
128                f"Can't overload {self.value} in {type(self).__name__}, Please use `.value` attribute.",
129            )
130        return int(self.value)
131
132    def __or__(self, other: typing.Union[Flag, int]) -> Flag:
133        return self.__class__(self._value_ | int(other))
134
135    def __xor__(self, other: typing.Union[Flag, int]) -> Flag:
136        return self.__class__(self._value_ ^ int(other))
137
138    def __and__(self, other: typing.Union[Flag, int]) -> Flag:
139        return self.__class__(other & int(other))
140
141    def __invert__(self) -> Flag:
142        return self.__class__(~self._value_)
143
144    def __contains__(self, other: typing.Union[Flag, int]) -> bool:
145        return self.value & int(other) == int(other)

Builtin Python enum flag with extra handlings.

name: str
value: int
class FlatIterator(typing.Generic[~Item]):
 43class FlatIterator(typing.Generic[Item]):
 44    """A Flat, In-Memory iterator for sequenced based data.
 45
 46    This can either be used sync or asynchronously.
 47
 48    Example
 49    -------
 50    ```py
 51    iterator = FlatIterator([1, 2, 3])
 52
 53    # Limit the results to 2.
 54    async for item in iterator.take(2):
 55        print(item)
 56    # 1
 57    # 2
 58
 59    # Filter the results.
 60    async for item in iterator.filter(lambda item: item > 1):
 61        print(item)
 62        print(iterator.count())
 63    # 2
 64    # 3
 65    # 3
 66
 67    # Map the results.
 68    async for item in iterator.map(lambda item: item * 2):
 69        print(item)
 70    # 2
 71    # 4
 72
 73    # This also works synchronously.
 74    iterator = FlatIterator(["Hello", "World", "!"])
 75    for item in iterator.discard(lambda item: "!" in item):
 76        print(item)
 77    # Hello
 78    # World
 79
 80    # Indexing is also supported.
 81
 82    print(iterator[0])
 83    # Hello
 84    ```
 85
 86    Parameters
 87    ----------
 88    items: `collections.Iterable[Item]`
 89        The items to iterate over.
 90    """
 91
 92    __slots__ = ("_items",)
 93
 94    def __init__(self, items: collections.Iterable[Item]) -> None:
 95        self._items = iter(items)
 96
 97    @typing.overload
 98    def collect(self) -> list[Item]:
 99        ...
100
101    @typing.overload
102    def collect(self, casting: _B) -> list[_B]:
103        """Collects all items in the iterator into a list and cast them into an object if provided.
104
105        Example
106        -------
107        >>> iterator = FlatIterator([1, 2, 3])
108        >>> iterator.collect(casting=str)
109        ["1", "2", "3"]
110
111        Parameters
112        ----------
113        casting: `T | None`
114            The type to cast the items to. If `None` is provided, the items will be returned as is.
115
116        Raises
117        ------
118        `StopIteration`
119            If no elements are left in the iterator.
120        """
121        ...
122
123    def collect(
124        self, casting: typing.Optional[_B] = None
125    ) -> typing.Union[list[Item], list[_B]]:
126        """Collects all items in the iterator into a list.
127
128        Example
129        -------
130        >>> iterator = FlatIterator([1, 2, 3])
131        >>> iterator.collect()
132        [1, 2, 3]
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        if casting is not None:
140            return typing.cast(list[_B], list(map(casting, self._items)))
141
142        return list(self._items)
143
144    def next(self) -> Item:
145        """Returns the next item in the iterator.
146
147        Example
148        -------
149        >>> iterator = FlatIterator[str](["1", "2", "3"])
150        item = iterator.next()
151        assert item == "1"
152        item = iterator.next()
153        assert item == "2"
154
155        Raises
156        ------
157        `StopIteration`
158            If no elements are left in the iterator.
159        """
160        try:
161            return self.__next__()
162        except StopIteration:
163            self._ok()
164
165    def map(
166        self, predicate: collections.Callable[[Item], OtherItem]
167    ) -> FlatIterator[OtherItem]:
168        """Maps each item in the iterator to its predicated value.
169
170        Example
171        -------
172        >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
173        <FlatIterator([1, 2, 3])>
174        >>> async for item in iterator:
175                assert isinstance(item, int)
176
177        Parameters
178        ----------
179        predicate: `collections.Callable[[Item], Item]`
180            The function to map each item in the iterator to its predicated value.
181
182        Raises
183        ------
184        `StopIteration`
185            If no elements are left in the iterator.
186        """
187        return FlatIterator(map(predicate, self._items))
188
189    def take(self, n: int) -> FlatIterator[Item]:
190        """Take the first number of items until the number of items are yielded or
191        the end of the iterator is reached.
192
193        Example
194        -------
195        >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
196        >>> async for mode in iterator.take(2):
197                assert mode in [GameMode.RAID, GameMode.STRIKE]
198        <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
199
200        Parameters
201        ----------
202        n: `int`
203            The number of items to take.
204
205        Raises
206        ------
207        `StopIteration`
208            If no elements are left in the iterator.
209        """
210        return FlatIterator(itertools.islice(self._items, n))
211
212    def take_while(
213        self, predicate: collections.Callable[[Item], bool]
214    ) -> FlatIterator[Item]:
215        """Yields items from the iterator while predicate returns `True`.
216
217        Example
218        -------
219        ```py
220        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
221
222        async for platform in (
223            iterator
224            .take_while(lambda platform: platform is not MembershipType.XBOX)
225        ):
226                print(platform)
227        # <FlatIterator([MembershipType.STEAM])>
228        ```
229
230        Parameters
231        ----------
232        predicate: `collections.Callable[[Item], bool]`
233            The function to predicate each item in the iterator.
234
235        Raises
236        ------
237        `StopIteration`
238            If no elements are left in the iterator.
239        """
240        return FlatIterator(itertools.takewhile(predicate, self._items))
241
242    def drop_while(
243        self, predicate: collections.Callable[[Item], bool]
244    ) -> FlatIterator[Item]:
245        """Yields items from the iterator while predicate returns `False`.
246
247        Example
248        -------
249        ```py
250        iterator = FlatIterator(
251            [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
252        )
253
254        async for membership in (
255            iterator
256            .drop_while(lambda membership: membership.name is not "Jim")
257        ):
258                print(membership)
259        # <FlatIterator([DestinyMembership(name="Bob")])>
260        ```
261
262        Parameters
263        ----------
264        predicate: `collections.Callable[[Item], bool]`
265            The function to predicate each item in the iterator.
266
267        Raises
268        ------
269        `StopIteration`
270            If no elements are left in the iterator.
271        """
272        return FlatIterator(itertools.dropwhile(predicate, self._items))
273
274    def filter(
275        self, predicate: collections.Callable[[Item], bool]
276    ) -> FlatIterator[Item]:
277        """Filters the iterator to only yield items that match the predicate.
278
279        Example
280        -------
281        ```py
282        activities = FlatIterator(
283            [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
284            # Assuming Raid is solo, Strike is flawless.
285        )
286
287        async for activity in (
288            activities
289            .filter(lambda activity: activity.is_solo or activity.is_flawless)
290        ):
291                print(member)
292        # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
293        ```
294        """
295        return FlatIterator(filter(predicate, self._items))
296
297    def skip(self, n: int) -> FlatIterator[Item]:
298        """Skips the first number of items in the iterator.
299
300        Example
301        -------
302        ```py
303        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
304
305        async for platform in iterator.skip(1):
306                print(platform)
307        # Skip the first item in the iterator.
308        # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
309        """
310        return FlatIterator(itertools.islice(self._items, n, None))
311
312    def discard(
313        self, predicate: collections.Callable[[Item], bool]
314    ) -> FlatIterator[Item]:
315        """Discards all elements in the iterator for which the predicate function returns true.
316
317        Example
318        -------
319        >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
320        >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
321                # Drops all memberships that are not steam.
322                print(iterator)
323        <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
324
325        Parameters
326        ----------
327        predicate: `collections.Callable[[Item], bool]`
328            The function to test each item in the iterator.
329
330        Raises
331        ------
332        `StopIteration`
333            If no elements are left in the iterator.
334        """
335        return FlatIterator(filter(lambda x: not predicate(x), self._items))
336
337    def zip(
338        self, other: FlatIterator[OtherItem]
339    ) -> FlatIterator[tuple[Item, OtherItem]]:
340        """Zips the iterator with another iterable.
341
342        Example
343        -------
344        >>> iterator = FlatIterator([1, 2, 3])
345        >>> other = FlatIterator([4, 5, 6])
346        >>> async for item, other_item in iterator.zip(other):
347                assert item == other_item
348        <FlatIterator([(1, 4), (2, 5), (3, 6)])>
349
350        Parameters
351        ----------
352        other: `FlatIterator[OtherItem]`
353            The iterable to zip with.
354
355        Raises
356        ------
357        `StopIteration`
358            If no elements are left in the iterator.
359        """
360        return FlatIterator(zip(self._items, other))
361
362    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
363        """`True` if all items in the iterator match the predicate.
364
365        Example
366        -------
367        >>> iterator = FlatIterator([1, 2, 3])
368        >>> while iterator.all(lambda item: isinstance(item, int)):
369                print("Still all integers")
370                continue
371            # Still all integers
372
373        Parameters
374        ----------
375        predicate: `collections.Callable[[Item], bool]`
376            The function to test each item in the iterator.
377
378        Raises
379        ------
380        `StopIteration`
381            If no elements are left in the iterator.
382        """
383        return all(predicate(item) for item in self)
384
385    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
386        """`True` if any items in the iterator match the predicate.
387
388        Example
389        -------
390        >>> iterator = FlatIterator([1, 2, 3])
391        >>> if iterator.any(lambda item: isinstance(item, int)):
392                print("At least one item is an int.")
393        # At least one item is an int.
394
395        Parameters
396        ----------
397        predicate: `collections.Callable[[Item], bool]`
398            The function to test each item in the iterator.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return any(predicate(item) for item in self)
406
407    def sort(
408        self,
409        *,
410        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
411        reverse: bool = False,
412    ) -> FlatIterator[Item]:
413        """Sorts the iterator.
414
415        Example
416        -------
417        >>> iterator = FlatIterator([3, 1, 6, 7])
418        >>> async for item in iterator.sort(key=lambda item: item < 3):
419                print(item)
420        # 1
421        # 3
422        # 6
423        # 7
424
425        Parameters
426        ----------
427        key: `collections.Callable[[Item], Any]`
428            The function to sort by.
429        reverse: `bool`
430            Whether to reverse the sort.
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return FlatIterator(sorted(self._items, key=key, reverse=reverse))
438
439    def first(self) -> Item:
440        """Returns the first item in the iterator.
441
442        Example
443        -------
444        >>> iterator = FlatIterator([3, 1, 6, 7])
445        >>> iterator.first()
446        3
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return self.take(1).next()
454
455    def reversed(self) -> FlatIterator[Item]:
456        """Returns a new iterator that yields the items in the iterator in reverse order.
457
458        Example
459        -------
460        >>> iterator = FlatIterator([3, 1, 6, 7])
461        >>> async for item in iterator.reversed():
462                print(item)
463        # 7
464        # 6
465        # 1
466        # 3
467
468        Raises
469        ------
470        `StopIteration`
471            If no elements are left in the iterator.
472        """
473        return FlatIterator(reversed(self.collect()))
474
475    def count(self) -> int:
476        count = 0
477        for _ in self:
478            count += 1
479
480        return count
481
482    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
483        """Returns a new iterator that yields all items from both iterators.
484
485        Example
486        -------
487        >>> iterator = FlatIterator([1, 2, 3])
488        >>> other = FlatIterator([4, 5, 6])
489        >>> async for item in iterator.union(other):
490                print(item)
491        # 1
492        # 2
493        # 3
494        # 4
495        # 5
496        # 6
497
498        Parameters
499        ----------
500        other: `FlatIterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return FlatIterator(itertools.chain(self._items, other))
509
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        >>> iterator = FlatIterator([1, 2, 3])
516        >>> iterator.for_each(lambda item: print(item))
517        # 1
518        # 2
519        # 3
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)
528
529    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
530        """Returns a new iterator that yields tuples of the index and item.
531
532        Example
533        -------
534        >>> iterator = FlatIterator([1, 2, 3])
535        >>> async for index, item in iterator.enumerate():
536                print(index, item)
537
538        # 0, 1
539        # 1, 2
540        # 2, 3
541
542        Raises
543        ------
544        `StopIteration`
545            If no elements are left in the iterator.
546        """
547        return FlatIterator(enumerate(self._items, start=start))
548
549    def _ok(self) -> typing.NoReturn:
550        raise StopIteration("No more items in the iterator.") from None
551
552    def __getitem__(self, index: int) -> Item:
553        try:
554            return self.skip(index).first()
555        except IndexError:
556            self._ok()
557
558    # This is a never.
559    def __setitem__(self) -> typing.NoReturn:
560        raise TypeError(
561            f"{type(self).__name__} doesn't support item assignment."
562        ) from None
563
564    def __repr__(self) -> str:
565        return f'<{self.__class__.__name__}({", ".join([str(item) for item in self])})>'
566
567    def __len__(self) -> int:
568        return self.count()
569
570    # We support both sync and async iter.
571    def __iter__(self) -> FlatIterator[Item]:
572        return self
573
574    def __aiter__(self) -> FlatIterator[Item]:
575        return self
576
577    def __next__(self) -> Item:
578        try:
579            item = next(self._items)
580        except StopIteration:
581            self._ok()
582
583        return item
584
585    async def __anext__(self) -> Item:
586        try:
587            item = next(self._items)
588        except StopIteration as e:
589            raise StopAsyncIteration from e
590
591        return item

A Flat, In-Memory iterator for sequenced based data.

This can either be used sync or asynchronously.

Example
iterator = FlatIterator([1, 2, 3])

# Limit the results to 2.
async for item in iterator.take(2):
    print(item)
# 1
# 2

# Filter the results.
async for item in iterator.filter(lambda item: item > 1):
    print(item)
    print(iterator.count())
# 2
# 3
# 3

# Map the results.
async for item in iterator.map(lambda item: item * 2):
    print(item)
# 2
# 4

# This also works synchronously.
iterator = FlatIterator(["Hello", "World", "!"])
for item in iterator.discard(lambda item: "!" in item):
    print(item)
# Hello
# World

# Indexing is also supported.

print(iterator[0])
# Hello
Parameters
  • items (collections.Iterable[Item]): The items to iterate over.
FlatIterator(items: collections.abc.Iterable[~Item])
94    def __init__(self, items: collections.Iterable[Item]) -> None:
95        self._items = iter(items)
def collect( self, casting: 'typing.Optional[_B]' = None) -> 'typing.Union[list[Item], list[_B]]':
123    def collect(
124        self, casting: typing.Optional[_B] = None
125    ) -> typing.Union[list[Item], list[_B]]:
126        """Collects all items in the iterator into a list.
127
128        Example
129        -------
130        >>> iterator = FlatIterator([1, 2, 3])
131        >>> iterator.collect()
132        [1, 2, 3]
133
134        Raises
135        ------
136        `StopIteration`
137            If no elements are left in the iterator.
138        """
139        if casting is not None:
140            return typing.cast(list[_B], list(map(casting, self._items)))
141
142        return list(self._items)

Collects all items in the iterator into a list.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.collect()
[1, 2, 3]
Raises
  • StopIteration: If no elements are left in the iterator.
def next(self) -> ~Item:
144    def next(self) -> Item:
145        """Returns the next item in the iterator.
146
147        Example
148        -------
149        >>> iterator = FlatIterator[str](["1", "2", "3"])
150        item = iterator.next()
151        assert item == "1"
152        item = iterator.next()
153        assert item == "2"
154
155        Raises
156        ------
157        `StopIteration`
158            If no elements are left in the iterator.
159        """
160        try:
161            return self.__next__()
162        except StopIteration:
163            self._ok()

Returns the next item in the iterator.

Example
>>> iterator = FlatIterator[str](["1", "2", "3"])
item = iterator.next()
assert item == "1"
item = iterator.next()
assert item == "2"
Raises
  • StopIteration: If no elements are left in the iterator.
def map( self, predicate: 'collections.Callable[[Item], OtherItem]') -> 'FlatIterator[OtherItem]':
165    def map(
166        self, predicate: collections.Callable[[Item], OtherItem]
167    ) -> FlatIterator[OtherItem]:
168        """Maps each item in the iterator to its predicated value.
169
170        Example
171        -------
172        >>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
173        <FlatIterator([1, 2, 3])>
174        >>> async for item in iterator:
175                assert isinstance(item, int)
176
177        Parameters
178        ----------
179        predicate: `collections.Callable[[Item], Item]`
180            The function to map each item in the iterator to its predicated value.
181
182        Raises
183        ------
184        `StopIteration`
185            If no elements are left in the iterator.
186        """
187        return FlatIterator(map(predicate, self._items))

Maps each item in the iterator to its predicated value.

Example
>>> iterator = FlatIterator[str](["1", "2", "3"]).map(lambda value: int(value))
<FlatIterator([1, 2, 3])>
>>> async for item in iterator:
        assert isinstance(item, int)
Parameters
  • predicate (collections.Callable[[Item], Item]): The function to map each item in the iterator to its predicated value.
Raises
  • StopIteration: If no elements are left in the iterator.
def take(self, n: int) -> aiobungie.FlatIterator[~Item]:
189    def take(self, n: int) -> FlatIterator[Item]:
190        """Take the first number of items until the number of items are yielded or
191        the end of the iterator is reached.
192
193        Example
194        -------
195        >>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
196        >>> async for mode in iterator.take(2):
197                assert mode in [GameMode.RAID, GameMode.STRIKE]
198        <FlatIterator([GameMode.RAID, GameMode.STRIKE])>
199
200        Parameters
201        ----------
202        n: `int`
203            The number of items to take.
204
205        Raises
206        ------
207        `StopIteration`
208            If no elements are left in the iterator.
209        """
210        return FlatIterator(itertools.islice(self._items, n))

Take the first number of items until the number of items are yielded or the end of the iterator is reached.

Example
>>> iterator = FlatIterator([GameMode.RAID, GameMode.STRIKE, GameMode.GAMBIT])
>>> async for mode in iterator.take(2):
        assert mode in [GameMode.RAID, GameMode.STRIKE]
<FlatIterator([GameMode.RAID, GameMode.STRIKE])>
Parameters
  • n (int): The number of items to take.
Raises
  • StopIteration: If no elements are left in the iterator.
def take_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
212    def take_while(
213        self, predicate: collections.Callable[[Item], bool]
214    ) -> FlatIterator[Item]:
215        """Yields items from the iterator while predicate returns `True`.
216
217        Example
218        -------
219        ```py
220        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
221
222        async for platform in (
223            iterator
224            .take_while(lambda platform: platform is not MembershipType.XBOX)
225        ):
226                print(platform)
227        # <FlatIterator([MembershipType.STEAM])>
228        ```
229
230        Parameters
231        ----------
232        predicate: `collections.Callable[[Item], bool]`
233            The function to predicate each item in the iterator.
234
235        Raises
236        ------
237        `StopIteration`
238            If no elements are left in the iterator.
239        """
240        return FlatIterator(itertools.takewhile(predicate, self._items))

Yields items from the iterator while predicate returns True.

Example
iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])

async for platform in (
    iterator
    .take_while(lambda platform: platform is not MembershipType.XBOX)
):
        print(platform)
# <FlatIterator([MembershipType.STEAM])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def drop_while( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
242    def drop_while(
243        self, predicate: collections.Callable[[Item], bool]
244    ) -> FlatIterator[Item]:
245        """Yields items from the iterator while predicate returns `False`.
246
247        Example
248        -------
249        ```py
250        iterator = FlatIterator(
251            [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
252        )
253
254        async for membership in (
255            iterator
256            .drop_while(lambda membership: membership.name is not "Jim")
257        ):
258                print(membership)
259        # <FlatIterator([DestinyMembership(name="Bob")])>
260        ```
261
262        Parameters
263        ----------
264        predicate: `collections.Callable[[Item], bool]`
265            The function to predicate each item in the iterator.
266
267        Raises
268        ------
269        `StopIteration`
270            If no elements are left in the iterator.
271        """
272        return FlatIterator(itertools.dropwhile(predicate, self._items))

Yields items from the iterator while predicate returns False.

Example
iterator = FlatIterator(
    [DestinyMembership(name="Fate"), DestinyMembership(name="Jim"), DestinyMembership(name="Bob")]
)

async for membership in (
    iterator
    .drop_while(lambda membership: membership.name is not "Jim")
):
        print(membership)
# <FlatIterator([DestinyMembership(name="Bob")])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to predicate each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def filter( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
274    def filter(
275        self, predicate: collections.Callable[[Item], bool]
276    ) -> FlatIterator[Item]:
277        """Filters the iterator to only yield items that match the predicate.
278
279        Example
280        -------
281        ```py
282        activities = FlatIterator(
283            [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
284            # Assuming Raid is solo, Strike is flawless.
285        )
286
287        async for activity in (
288            activities
289            .filter(lambda activity: activity.is_solo or activity.is_flawless)
290        ):
291                print(member)
292        # <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
293        ```
294        """
295        return FlatIterator(filter(predicate, self._items))

Filters the iterator to only yield items that match the predicate.

Example
activities = FlatIterator(
    [Activity(mode=GameMode.RAID), Activity(mode=GameMode.DUNGEON), Activity(mode=GameMode.STRIKE)]
    # Assuming Raid is solo, Strike is flawless.
)

async for activity in (
    activities
    .filter(lambda activity: activity.is_solo or activity.is_flawless)
):
        print(member)
# <FlatIterator([Activity(mode=GameMode.RAID), Activity(mode=GameMode.STRIKE)])>
def skip(self, n: int) -> aiobungie.FlatIterator[~Item]:
297    def skip(self, n: int) -> FlatIterator[Item]:
298        """Skips the first number of items in the iterator.
299
300        Example
301        -------
302        ```py
303        iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
304
305        async for platform in iterator.skip(1):
306                print(platform)
307        # Skip the first item in the iterator.
308        # <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
309        """
310        return FlatIterator(itertools.islice(self._items, n, None))

Skips the first number of items in the iterator.

Example

```py iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])

async for platform in iterator.skip(1): print(platform)

Skip the first item in the iterator.

MembershipType.XBOX, MembershipType.STADIA])>

def discard( self, predicate: collections.abc.Callable[[~Item], bool]) -> aiobungie.FlatIterator[~Item]:
312    def discard(
313        self, predicate: collections.Callable[[Item], bool]
314    ) -> FlatIterator[Item]:
315        """Discards all elements in the iterator for which the predicate function returns true.
316
317        Example
318        -------
319        >>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
320        >>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
321                # Drops all memberships that are not steam.
322                print(iterator)
323        <FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
324
325        Parameters
326        ----------
327        predicate: `collections.Callable[[Item], bool]`
328            The function to test each item in the iterator.
329
330        Raises
331        ------
332        `StopIteration`
333            If no elements are left in the iterator.
334        """
335        return FlatIterator(filter(lambda x: not predicate(x), self._items))

Discards all elements in the iterator for which the predicate function returns true.

Example
>>> iterator = FlatIterator([MembershipType.STEAM, MembershipType.XBOX, MembershipType.STADIA])
>>> async for _ in iterator.discard(lambda platform: platform is not MembershipType.STEAM):
        # Drops all memberships that are not steam.
        print(iterator)
<FlatIterator([MembershipType.XBOX, MembershipType.STADIA])>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def zip( self, other: 'FlatIterator[OtherItem]') -> 'FlatIterator[tuple[Item, OtherItem]]':
337    def zip(
338        self, other: FlatIterator[OtherItem]
339    ) -> FlatIterator[tuple[Item, OtherItem]]:
340        """Zips the iterator with another iterable.
341
342        Example
343        -------
344        >>> iterator = FlatIterator([1, 2, 3])
345        >>> other = FlatIterator([4, 5, 6])
346        >>> async for item, other_item in iterator.zip(other):
347                assert item == other_item
348        <FlatIterator([(1, 4), (2, 5), (3, 6)])>
349
350        Parameters
351        ----------
352        other: `FlatIterator[OtherItem]`
353            The iterable to zip with.
354
355        Raises
356        ------
357        `StopIteration`
358            If no elements are left in the iterator.
359        """
360        return FlatIterator(zip(self._items, other))

Zips the iterator with another iterable.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item, other_item in iterator.zip(other):
        assert item == other_item
<FlatIterator([(1, 4), (2, 5), (3, 6)])>
Parameters
  • other (FlatIterator[OtherItem]): The iterable to zip with.
Raises
  • StopIteration: If no elements are left in the iterator.
def all(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
362    def all(self, predicate: collections.Callable[[Item], bool]) -> bool:
363        """`True` if all items in the iterator match the predicate.
364
365        Example
366        -------
367        >>> iterator = FlatIterator([1, 2, 3])
368        >>> while iterator.all(lambda item: isinstance(item, int)):
369                print("Still all integers")
370                continue
371            # Still all integers
372
373        Parameters
374        ----------
375        predicate: `collections.Callable[[Item], bool]`
376            The function to test each item in the iterator.
377
378        Raises
379        ------
380        `StopIteration`
381            If no elements are left in the iterator.
382        """
383        return all(predicate(item) for item in self)

True if all items in the iterator match the predicate.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> while iterator.all(lambda item: isinstance(item, int)):
        print("Still all integers")
        continue
    # Still all integers
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def any(self, predicate: collections.abc.Callable[[~Item], bool]) -> bool:
385    def any(self, predicate: collections.Callable[[Item], bool]) -> bool:
386        """`True` if any items in the iterator match the predicate.
387
388        Example
389        -------
390        >>> iterator = FlatIterator([1, 2, 3])
391        >>> if iterator.any(lambda item: isinstance(item, int)):
392                print("At least one item is an int.")
393        # At least one item is an int.
394
395        Parameters
396        ----------
397        predicate: `collections.Callable[[Item], bool]`
398            The function to test each item in the iterator.
399
400        Raises
401        ------
402        `StopIteration`
403            If no elements are left in the iterator.
404        """
405        return any(predicate(item) for item in self)

True if any items in the iterator match the predicate.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> if iterator.any(lambda item: isinstance(item, int)):
        print("At least one item is an int.")
<h1 id="at-least-one-item-is-an-int">At least one item is an int.</h1>
Parameters
  • predicate (collections.Callable[[Item], bool]): The function to test each item in the iterator.
Raises
  • StopIteration: If no elements are left in the iterator.
def sort( self, *, key: 'collections.Callable[[Item], typeshed.SupportsRichComparison]', reverse: bool = False) -> aiobungie.FlatIterator[~Item]:
407    def sort(
408        self,
409        *,
410        key: collections.Callable[[Item], typeshed.SupportsRichComparison],
411        reverse: bool = False,
412    ) -> FlatIterator[Item]:
413        """Sorts the iterator.
414
415        Example
416        -------
417        >>> iterator = FlatIterator([3, 1, 6, 7])
418        >>> async for item in iterator.sort(key=lambda item: item < 3):
419                print(item)
420        # 1
421        # 3
422        # 6
423        # 7
424
425        Parameters
426        ----------
427        key: `collections.Callable[[Item], Any]`
428            The function to sort by.
429        reverse: `bool`
430            Whether to reverse the sort.
431
432        Raises
433        ------
434        `StopIteration`
435            If no elements are left in the iterator.
436        """
437        return FlatIterator(sorted(self._items, key=key, reverse=reverse))

Sorts the iterator.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.sort(key=lambda item: item < 3):
        print(item)
<h1 id="1">1</h1>

3

6

7

Parameters
  • key (collections.Callable[[Item], Any]): The function to sort by.
  • reverse (bool): Whether to reverse the sort.
Raises
  • StopIteration: If no elements are left in the iterator.
def first(self) -> ~Item:
439    def first(self) -> Item:
440        """Returns the first item in the iterator.
441
442        Example
443        -------
444        >>> iterator = FlatIterator([3, 1, 6, 7])
445        >>> iterator.first()
446        3
447
448        Raises
449        ------
450        `StopIteration`
451            If no elements are left in the iterator.
452        """
453        return self.take(1).next()

Returns the first item in the iterator.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> iterator.first()
3
Raises
  • StopIteration: If no elements are left in the iterator.
def reversed(self) -> aiobungie.FlatIterator[~Item]:
455    def reversed(self) -> FlatIterator[Item]:
456        """Returns a new iterator that yields the items in the iterator in reverse order.
457
458        Example
459        -------
460        >>> iterator = FlatIterator([3, 1, 6, 7])
461        >>> async for item in iterator.reversed():
462                print(item)
463        # 7
464        # 6
465        # 1
466        # 3
467
468        Raises
469        ------
470        `StopIteration`
471            If no elements are left in the iterator.
472        """
473        return FlatIterator(reversed(self.collect()))

Returns a new iterator that yields the items in the iterator in reverse order.

Example
>>> iterator = FlatIterator([3, 1, 6, 7])
>>> async for item in iterator.reversed():
        print(item)
<h1 id="7">7</h1>

6

1

3

Raises
  • StopIteration: If no elements are left in the iterator.
def count(self) -> int:
475    def count(self) -> int:
476        count = 0
477        for _ in self:
478            count += 1
479
480        return count
def union( self, other: aiobungie.FlatIterator[~Item]) -> aiobungie.FlatIterator[~Item]:
482    def union(self, other: FlatIterator[Item]) -> FlatIterator[Item]:
483        """Returns a new iterator that yields all items from both iterators.
484
485        Example
486        -------
487        >>> iterator = FlatIterator([1, 2, 3])
488        >>> other = FlatIterator([4, 5, 6])
489        >>> async for item in iterator.union(other):
490                print(item)
491        # 1
492        # 2
493        # 3
494        # 4
495        # 5
496        # 6
497
498        Parameters
499        ----------
500        other: `FlatIterator[Item]`
501            The iterable to union with.
502
503        Raises
504        ------
505        `StopIteration`
506            If no elements are left in the iterator.
507        """
508        return FlatIterator(itertools.chain(self._items, other))

Returns a new iterator that yields all items from both iterators.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> other = FlatIterator([4, 5, 6])
>>> async for item in iterator.union(other):
        print(item)
<h1 id="1">1</h1>

2

3

4

5

6

Parameters
  • other (FlatIterator[Item]): The iterable to union with.
Raises
  • StopIteration: If no elements are left in the iterator.
def for_each(self, func: collections.abc.Callable[[~Item], typing.Any]) -> None:
510    def for_each(self, func: collections.Callable[[Item], typing.Any]) -> None:
511        """Calls the function on each item in the iterator.
512
513        Example
514        -------
515        >>> iterator = FlatIterator([1, 2, 3])
516        >>> iterator.for_each(lambda item: print(item))
517        # 1
518        # 2
519        # 3
520
521        Parameters
522        ----------
523        func: `typeshed.Callable[[Item], None]`
524            The function to call on each item in the iterator.
525        """
526        for item in self:
527            func(item)

Calls the function on each item in the iterator.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> iterator.for_each(lambda item: print(item))
<h1 id="1">1</h1>

2

3

Parameters
  • func (typeshed.Callable[[Item], None]): The function to call on each item in the iterator.
def enumerate( self, *, start: int = 0) -> aiobungie.FlatIterator[tuple[int, ~Item]]:
529    def enumerate(self, *, start: int = 0) -> FlatIterator[tuple[int, Item]]:
530        """Returns a new iterator that yields tuples of the index and item.
531
532        Example
533        -------
534        >>> iterator = FlatIterator([1, 2, 3])
535        >>> async for index, item in iterator.enumerate():
536                print(index, item)
537
538        # 0, 1
539        # 1, 2
540        # 2, 3
541
542        Raises
543        ------
544        `StopIteration`
545            If no elements are left in the iterator.
546        """
547        return FlatIterator(enumerate(self._items, start=start))

Returns a new iterator that yields tuples of the index and item.

Example
>>> iterator = FlatIterator([1, 2, 3])
>>> async for index, item in iterator.enumerate():
        print(index, item)

0, 1

1, 2

2, 3

Raises
  • StopIteration: If no elements are left in the iterator.
@attrs.define(auto_exc=True)
class Forbidden(aiobungie.HTTPException):
133@attrs.define(auto_exc=True)
134class Forbidden(HTTPException):
135    """Exception that's raised for when status code 403 occurs."""
136
137    http_status: http.HTTPStatus = attrs.field(
138        default=http.HTTPStatus.FORBIDDEN, init=False
139    )

Exception that's raised for when status code 403 occurs.

Forbidden( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Forbidden.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class GameMode(builtins.int, aiobungie.Enum):
274@typing.final
275class GameMode(int, Enum):
276    """An Enum for all available gamemodes in Destiny 2."""
277
278    NONE = 0
279    STORY = 2
280    STRIKE = 3
281    RAID = 4
282    ALLPVP = 5
283    PATROL = 6
284    ALLPVE = 7
285    RESERVED9 = 9
286    CONTROL = 10
287    RESERVED11 = 11
288    CLASH = 12
289    RESERVED13 = 13
290    CRIMSONDOUBLES = 15
291    NIGHTFALL = 16
292    HEROICNIGHTFALL = 17
293    ALLSTRIKES = 18
294    IRONBANNER = 19
295    RESERVED20 = 20
296    RESERVED21 = 21
297    RESERVED22 = 22
298    RESERVED24 = 24
299    ALLMAYHEM = 25
300    RESERVED26 = 26
301    RESERVED27 = 27
302    RESERVED28 = 28
303    RESERVED29 = 29
304    RESERVED30 = 30
305    SUPREMACY = 31
306    PRIVATEMATCHESALL = 32
307    SURVIVAL = 37
308    COUNTDOWN = 38
309    TRIALSOFTHENINE = 39
310    SOCIAL = 40
311    TRIALSCOUNTDOWN = 41
312    TRIALSSURVIVAL = 42
313    IRONBANNERCONTROL = 43
314    IRONBANNERCLASH = 44
315    IRONBANNERSUPREMACY = 45
316    SCOREDNIGHTFALL = 46
317    SCOREDHEROICNIGHTFALL = 47
318    RUMBLE = 48
319    ALLDOUBLES = 49
320    DOUBLES = 50
321    PRIVATEMATCHESCLASH = 51
322    PRIVATEMATCHESCONTROL = 52
323    PRIVATEMATCHESSUPREMACY = 53
324    PRIVATEMATCHESCOUNTDOWN = 54
325    PRIVATEMATCHESSURVIVAL = 55
326    PRIVATEMATCHESMAYHEM = 56
327    PRIVATEMATCHESRUMBLE = 57
328    HEROICADVENTURE = 58
329    SHOWDOWN = 59
330    LOCKDOWN = 60
331    SCORCHED = 61
332    SCORCHEDTEAM = 62
333    GAMBIT = 63
334    ALLPVECOMPETITIVE = 64
335    BREAKTHROUGH = 65
336    BLACKARMORYRUN = 66
337    SALVAGE = 67
338    IRONBANNERSALVAGE = 68
339    PVPCOMPETITIVE = 69
340    PVPQUICKPLAY = 70
341    CLASHQUICKPLAY = 71
342    CLASHCOMPETITIVE = 72
343    CONTROLQUICKPLAY = 73
344    CONTROLCOMPETITIVE = 74
345    GAMBITPRIME = 75
346    RECKONING = 76
347    MENAGERIE = 77
348    VEXOFFENSIVE = 78
349    NIGHTMAREHUNT = 79
350    ELIMINATION = 80
351    MOMENTUM = 81
352    DUNGEON = 82
353    SUNDIAL = 83
354    TRIALS_OF_OSIRIS = 84
355    DARES = 85
356    OFFENSIVE = 86
357    LOSTSECTOR = 87
358    RIFT = 88
359    ZONECONTROL = 89
360    IRONBANNERRIFT = 90

An Enum for all available gamemodes in Destiny 2.

NONE = <GameMode.NONE: 0>
STORY = <GameMode.STORY: 2>
STRIKE = <GameMode.STRIKE: 3>
RAID = <GameMode.RAID: 4>
ALLPVP = <GameMode.ALLPVP: 5>
PATROL = <GameMode.PATROL: 6>
ALLPVE = <GameMode.ALLPVE: 7>
RESERVED9 = <GameMode.RESERVED9: 9>
CONTROL = <GameMode.CONTROL: 10>
RESERVED11 = <GameMode.RESERVED11: 11>
CLASH = <GameMode.CLASH: 12>
RESERVED13 = <GameMode.RESERVED13: 13>
CRIMSONDOUBLES = <GameMode.CRIMSONDOUBLES: 15>
NIGHTFALL = <GameMode.NIGHTFALL: 16>
HEROICNIGHTFALL = <GameMode.HEROICNIGHTFALL: 17>
ALLSTRIKES = <GameMode.ALLSTRIKES: 18>
IRONBANNER = <GameMode.IRONBANNER: 19>
RESERVED20 = <GameMode.RESERVED20: 20>
RESERVED21 = <GameMode.RESERVED21: 21>
RESERVED22 = <GameMode.RESERVED22: 22>
RESERVED24 = <GameMode.RESERVED24: 24>
ALLMAYHEM = <GameMode.ALLMAYHEM: 25>
RESERVED26 = <GameMode.RESERVED26: 26>
RESERVED27 = <GameMode.RESERVED27: 27>
RESERVED28 = <GameMode.RESERVED28: 28>
RESERVED29 = <GameMode.RESERVED29: 29>
RESERVED30 = <GameMode.RESERVED30: 30>
SUPREMACY = <GameMode.SUPREMACY: 31>
PRIVATEMATCHESALL = <GameMode.PRIVATEMATCHESALL: 32>
SURVIVAL = <GameMode.SURVIVAL: 37>
COUNTDOWN = <GameMode.COUNTDOWN: 38>
TRIALSOFTHENINE = <GameMode.TRIALSOFTHENINE: 39>
SOCIAL = <GameMode.SOCIAL: 40>
TRIALSCOUNTDOWN = <GameMode.TRIALSCOUNTDOWN: 41>
TRIALSSURVIVAL = <GameMode.TRIALSSURVIVAL: 42>
IRONBANNERCONTROL = <GameMode.IRONBANNERCONTROL: 43>
IRONBANNERCLASH = <GameMode.IRONBANNERCLASH: 44>
IRONBANNERSUPREMACY = <GameMode.IRONBANNERSUPREMACY: 45>
SCOREDNIGHTFALL = <GameMode.SCOREDNIGHTFALL: 46>
SCOREDHEROICNIGHTFALL = <GameMode.SCOREDHEROICNIGHTFALL: 47>
RUMBLE = <GameMode.RUMBLE: 48>
ALLDOUBLES = <GameMode.ALLDOUBLES: 49>
DOUBLES = <GameMode.DOUBLES: 50>
PRIVATEMATCHESCLASH = <GameMode.PRIVATEMATCHESCLASH: 51>
PRIVATEMATCHESCONTROL = <GameMode.PRIVATEMATCHESCONTROL: 52>
PRIVATEMATCHESSUPREMACY = <GameMode.PRIVATEMATCHESSUPREMACY: 53>
PRIVATEMATCHESCOUNTDOWN = <GameMode.PRIVATEMATCHESCOUNTDOWN: 54>
PRIVATEMATCHESSURVIVAL = <GameMode.PRIVATEMATCHESSURVIVAL: 55>
PRIVATEMATCHESMAYHEM = <GameMode.PRIVATEMATCHESMAYHEM: 56>
PRIVATEMATCHESRUMBLE = <GameMode.PRIVATEMATCHESRUMBLE: 57>
HEROICADVENTURE = <GameMode.HEROICADVENTURE: 58>
SHOWDOWN = <GameMode.SHOWDOWN: 59>
LOCKDOWN = <GameMode.LOCKDOWN: 60>
SCORCHED = <GameMode.SCORCHED: 61>
SCORCHEDTEAM = <GameMode.SCORCHEDTEAM: 62>
GAMBIT = <GameMode.GAMBIT: 63>
ALLPVECOMPETITIVE = <GameMode.ALLPVECOMPETITIVE: 64>
BREAKTHROUGH = <GameMode.BREAKTHROUGH: 65>
BLACKARMORYRUN = <GameMode.BLACKARMORYRUN: 66>
SALVAGE = <GameMode.SALVAGE: 67>
IRONBANNERSALVAGE = <GameMode.IRONBANNERSALVAGE: 68>
PVPCOMPETITIVE = <GameMode.PVPCOMPETITIVE: 69>
PVPQUICKPLAY = <GameMode.PVPQUICKPLAY: 70>
CLASHQUICKPLAY = <GameMode.CLASHQUICKPLAY: 71>
CLASHCOMPETITIVE = <GameMode.CLASHCOMPETITIVE: 72>
CONTROLQUICKPLAY = <GameMode.CONTROLQUICKPLAY: 73>
CONTROLCOMPETITIVE = <GameMode.CONTROLCOMPETITIVE: 74>
GAMBITPRIME = <GameMode.GAMBITPRIME: 75>
RECKONING = <GameMode.RECKONING: 76>
MENAGERIE = <GameMode.MENAGERIE: 77>
VEXOFFENSIVE = <GameMode.VEXOFFENSIVE: 78>
NIGHTMAREHUNT = <GameMode.NIGHTMAREHUNT: 79>
ELIMINATION = <GameMode.ELIMINATION: 80>
MOMENTUM = <GameMode.MOMENTUM: 81>
DUNGEON = <GameMode.DUNGEON: 82>
SUNDIAL = <GameMode.SUNDIAL: 83>
TRIALS_OF_OSIRIS = <GameMode.TRIALS_OF_OSIRIS: 84>
DARES = <GameMode.DARES: 85>
OFFENSIVE = <GameMode.OFFENSIVE: 86>
LOSTSECTOR = <GameMode.LOSTSECTOR: 87>
RIFT = <GameMode.RIFT: 88>
ZONECONTROL = <GameMode.ZONECONTROL: 89>
IRONBANNERRIFT = <GameMode.IRONBANNERRIFT: 90>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GatingScope(builtins.int, aiobungie.Enum):
58@typing.final
59class GatingScope(int, enums.Enum):
60    """An enum represents restrictive type of gating that is being performed by an entity.
61
62    This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity
63    applies to everyone equally, or to their specific Profile or Character states.
64    """
65
66    NONE = 0
67    GLOBAL = 1
68    CLAN = 2
69    PROFILE = 3
70    CHARACTER = 4
71    ITEM = 5
72    ASSUMED_WORST_CASE = 6

An enum represents restrictive type of gating that is being performed by an entity.

This is useful as a shortcut to avoid a lot of lookups when determining whether the gating on an Entity applies to everyone equally, or to their specific Profile or Character states.

NONE = <GatingScope.NONE: 0>
GLOBAL = <GatingScope.GLOBAL: 1>
CLAN = <GatingScope.CLAN: 2>
PROFILE = <GatingScope.PROFILE: 3>
CHARACTER = <GatingScope.CHARACTER: 4>
ITEM = <GatingScope.ITEM: 5>
ASSUMED_WORST_CASE = <GatingScope.ASSUMED_WORST_CASE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Gender(builtins.int, aiobungie.Enum):
487@typing.final
488class Gender(int, Enum):
489    """An Enum for Destiny Genders."""
490
491    MALE = 0
492    FEMALE = 1
493    UNKNOWN = 2

An Enum for Destiny Genders.

MALE = <Gender.MALE: 0>
FEMALE = <Gender.FEMALE: 1>
UNKNOWN = <Gender.UNKNOWN: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class GroupType(builtins.int, aiobungie.Enum):
656@typing.final
657class GroupType(int, Enum):
658    """An enums for the known bungie group types."""
659
660    GENERAL = 0
661    CLAN = 1

An enums for the known bungie group types.

GENERAL = <GroupType.GENERAL: 0>
CLAN = <GroupType.CLAN: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class HTTPError(aiobungie.AiobungieError):
65@attrs.define(auto_exc=True)
66class HTTPError(AiobungieError):
67    """Exception base used for HTTP request errors."""
68
69    message: str
70    """The error message."""
71
72    http_status: http.HTTPStatus
73    """The response status."""

Exception base used for HTTP request errors.

HTTPError(message: str, http_status: http.HTTPStatus)
2def __init__(self, message, http_status):
3    self.message = message
4    self.http_status = http_status
5    BaseException.__init__(self, self.message,self.http_status)

Method generated by attrs for class HTTPError.

message: str

The error message.

http_status: http.HTTPStatus

The response status.

Inherited Members
builtins.BaseException
with_traceback
args
@attrs.define(auto_exc=True, kw_only=True)
class HTTPException(aiobungie.HTTPError):
 86@attrs.define(auto_exc=True, kw_only=True)
 87class HTTPException(HTTPError):
 88    """Exception base internally used for an HTTP request response errors."""
 89
 90    error_code: int
 91    """The returned Bungie error status code."""
 92
 93    http_status: http.HTTPStatus
 94    """The request response http status."""
 95
 96    throttle_seconds: int
 97    """The Bungie response throttle seconds."""
 98
 99    url: typing.Optional[typedefs.StrOrURL]
100    """The URL/endpoint caused this error."""
101
102    body: typing.Any
103    """The response body."""
104
105    headers: multidict.CIMultiDictProxy[str]
106    """The response headers."""
107
108    message: str
109    """A Bungie human readable message describes the cause of the error."""
110
111    error_status: str
112    """A Bungie short error status describes the cause of the error."""
113
114    message_data: dict[str, str]
115    """A dict of string key, value that includes each cause of the error
116    to a message describes information about that error.
117    """
118
119    def __str__(self) -> str:
120        if self.message:
121            message_body = self.message
122
123        if self.error_status:
124            error_status_body = self.error_status
125
126        return (
127            f"{self.http_status.name.replace('_', '').title()} {self.http_status.value}: "
128            f"Error status: {error_status_body}, Error message: {message_body} from {self.url} "
129            f"{str(self.body)}"
130        )

Exception base internally used for an HTTP request response errors.

HTTPException( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class HTTPException.

error_code: int

The returned Bungie error status code.

http_status: http.HTTPStatus

The request response http status.

throttle_seconds: int

The Bungie response throttle seconds.

url: Union[str, yarl.URL, NoneType]

The URL/endpoint caused this error.

body: Any

The response body.

headers: multidict._multidict.CIMultiDictProxy[str]

The response headers.

message: str

A Bungie human readable message describes the cause of the error.

error_status: str

A Bungie short error status describes the cause of the error.

message_data: dict[str, str]

A dict of string key, value that includes each cause of the error to a message describes information about that error.

Inherited Members
builtins.BaseException
with_traceback
args
class Image:
 72class Image:
 73    """Representation of an image/avatar/picture at Bungie.
 74
 75    Example
 76    -------
 77    ```py
 78    from aiobungie import Image
 79    img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
 80    print(img)
 81    # https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg
 82
 83    # Stream the image.
 84    async for chunk in img:
 85        # Byte chunks of the image.
 86        print(chunk)
 87
 88    # Save the image to a file.
 89    await img.save("file_name", "/my/path/to/save/to", "jpeg")
 90    ```
 91
 92    Parameters
 93    ----------
 94    path : `str | None`
 95        The path to the image. If `None`, the default missing image path will be used.
 96    """
 97
 98    __slots__ = ("_path",)
 99
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
102
103    @property
104    def is_missing(self) -> bool:
105        return not self._path
106
107    @property
108    def url(self) -> str:
109        """The URL to the image."""
110        return self.create_url()
111
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"
116
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"
126
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err
181
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader
204
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk
224
225    def __repr__(self) -> str:
226        return f"Image(url={self.create_url()})"
227
228    def __str__(self) -> str:
229        return self.create_url()
230
231    def __aiter__(self) -> Image:
232        return self
233
234    async def __anext__(self) -> bytes:
235        return await self.read()
236
237    def __await__(self) -> collections.Generator[None, None, bytes]:
238        return self.__anext__().__await__()

Representation of an image/avatar/picture at Bungie.

Example
from aiobungie import Image
img = Image("img/destiny_content/pgcr/raid_eclipse.jpg")
print(img)
# https://www.bungie.net/img/destiny_content/pgcr/raid_eclipse.jpg

# Stream the image.
async for chunk in img:
    # Byte chunks of the image.
    print(chunk)

# Save the image to a file.
await img.save("file_name", "/my/path/to/save/to", "jpeg")
Parameters
  • path (str | None): The path to the image. If None, the default missing image path will be used.
Image(path: Optional[str] = None)
100    def __init__(self, path: typing.Optional[str] = None) -> None:
101        self._path = path
is_missing: bool
url: str

The URL to the image.

@staticmethod
def missing_path() -> str:
112    @staticmethod
113    def missing_path() -> str:
114        """Returns the path to the missing Bungie image."""
115        return "img/misc/missing_icon_d2.png"

Returns the path to the missing Bungie image.

def create_url(self) -> str:
117    def create_url(self) -> str:
118        """Creates a full URL to the image path.
119
120        Returns
121        -------
122        str
123            The URL to the image.
124        """
125        return f"{url.BASE}/{self._path if self._path else self.missing_path()}"

Creates a full URL to the image path.

Returns
  • str: The URL to the image.
async def save( self, file_name: str, path: Union[pathlib.Path, str], /, mime_type: Union[aiobungie.internal.assets.MimeType, str, NoneType] = None) -> None:
127    async def save(
128        self,
129        file_name: str,
130        path: typing.Union[pathlib.Path, str],
131        /,
132        mime_type: typing.Optional[typing.Union[MimeType, str]] = None,
133    ) -> None:
134        """Saves the image to a file.
135
136        Parameters
137        ----------
138        file_name : `str`
139            A name for the file to save the image to.
140        path : `pathlib.Path | str`
141            A path tp save the image to.
142
143        Other Parameters
144        ----------------
145        mime_type : `MimeType | str`
146            Optional MIME type of the image.
147
148        Raises
149        ------
150        `FileNotFoundError`
151            If the path provided does not exist.
152        `RuntimeError`
153            If the image could not be saved.
154        `PermissionError`
155            If the path provided is not writable or does not have write permissions.
156        """
157        if isinstance(path, pathlib.Path) and not path.exists():
158            raise FileNotFoundError(f"File does not exist: {path!r}")
159
160        if self.is_missing:
161            return
162
163        mimetype = mime_type or MimeType.PNG
164        path = pathlib.Path(path)
165
166        loop = helpers.get_or_make_loop()
167        pool = concurrent.futures.ThreadPoolExecutor()
168
169        try:
170            with pool:
171                await loop.run_in_executor(
172                    pool, _write, path, file_name, mimetype, await self.read()
173                )
174                _LOGGER.info("Saved image to %s", file_name)
175
176        except asyncio.CancelledError:
177            pass
178
179        except Exception as err:
180            raise RuntimeError("Encountered an error while saving image.") from err

Saves the image to a file.

Parameters
  • file_name (str): A name for the file to save the image to.
  • path (pathlib.Path | str): A path tp save the image to.
Other Parameters
  • mime_type (MimeType | str): Optional MIME type of the image.
Raises
  • FileNotFoundError: If the path provided does not exist.
  • RuntimeError: If the image could not be saved.
  • PermissionError: If the path provided is not writable or does not have write permissions.
async def read(self) -> bytes:
182    async def read(self) -> bytes:
183        """Read this image bytes.
184
185        Returns
186        -------
187        `bytes`
188            The bytes of this image.
189        """
190        client_session = aiohttp.ClientSession()
191
192        try:
193            await client_session.__aenter__()
194            response = await client_session.get(self.create_url())
195
196            if 300 >= response.status >= 200:
197                reader = await response.read()
198
199        except Exception as exc:
200            raise RuntimeError(f"Failed to read image: {exc}") from None
201        finally:
202            await client_session.__aexit__(None, None, None)
203        return reader

Read this image bytes.

Returns
  • bytes: The bytes of this image.
async def iter(self) -> collections.abc.AsyncGenerator[bytes, None]:
205    async def iter(self) -> collections.AsyncGenerator[bytes, None]:
206        """Iterates over the image bytes lazily.
207
208        Example
209        -------
210        import aiobungie
211
212        resource = aiobungie.Image("img/misc/missing_icon_d2.png")
213        async for chunk in resource.iter():
214            print(chunk)
215
216        Returns
217        -------
218        `collections.AsyncGenerator[bytes, None]`
219            An async generator of the image bytes.
220        """
221
222        async for chunk in self:
223            yield chunk

Iterates over the image bytes lazily.

Example

import aiobungie

resource = aiobungie.Image("img/misc/missing_icon_d2.png") async for chunk in resource.iter(): print(chunk)

Returns
  • collections.AsyncGenerator[bytes, None]: An async generator of the image bytes.
@attrs.define(auto_exc=True)
class InternalServerError(aiobungie.HTTPException):
203@attrs.define(auto_exc=True)
204class InternalServerError(HTTPException):
205    """Raised for 5xx internal server errors."""

Raised for 5xx internal server errors.

InternalServerError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class InternalServerError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ItemBindStatus(builtins.int, aiobungie.Enum):
722@typing.final
723class ItemBindStatus(int, Enum):
724    """An enum for Destiny 2 items bind status."""
725
726    NOT_BOUND = 0
727    BOUND_TO_CHARACTER = 1
728    BOUND_TO_ACCOUNT = 2
729    BOUNT_TO_GUILD = 3

An enum for Destiny 2 items bind status.

NOT_BOUND = <ItemBindStatus.NOT_BOUND: 0>
BOUND_TO_CHARACTER = <ItemBindStatus.BOUND_TO_CHARACTER: 1>
BOUND_TO_ACCOUNT = <ItemBindStatus.BOUND_TO_ACCOUNT: 2>
BOUNT_TO_GUILD = <ItemBindStatus.BOUNT_TO_GUILD: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemLocation(builtins.int, aiobungie.Enum):
732@typing.final
733class ItemLocation(int, Enum):
734    """An enum for Destiny 2 items location."""
735
736    UNKNOWN = 0
737    INVENTORY = 1
738    VAULT = 2
739    VENDOR = 3
740    POSTMASTER = 4

An enum for Destiny 2 items location.

UNKNOWN = <ItemLocation.UNKNOWN: 0>
INVENTORY = <ItemLocation.INVENTORY: 1>
VAULT = <ItemLocation.VAULT: 2>
VENDOR = <ItemLocation.VENDOR: 3>
POSTMASTER = <ItemLocation.POSTMASTER: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemState(aiobungie.Flag):
757@typing.final
758class ItemState(Flag):
759    """An enum for Destiny 2 item states."""
760
761    NONE = 0
762    LOCKED = 1
763    TRACKED = 2
764    MASTERWORKED = 4
765    CRAFTED = 8
766    """If this bit is set, the item has been 'crafted' by the player."""
767    HIGHLITED_OBJECTIVE = 16
768    """If this bit is set, the item is a 'highlighted' objective."""

An enum for Destiny 2 item states.

NONE = <ItemState.NONE: 0>
LOCKED = <ItemState.LOCKED: 1>
TRACKED = <ItemState.TRACKED: 2>
MASTERWORKED = <ItemState.MASTERWORKED: 4>
CRAFTED = <ItemState.CRAFTED: 8>

If this bit is set, the item has been 'crafted' by the player.

HIGHLITED_OBJECTIVE = <ItemState.HIGHLITED_OBJECTIVE: 16>

If this bit is set, the item is a 'highlighted' objective.

Inherited Members
Flag
name
value
@typing.final
class ItemSubType(builtins.int, aiobungie.Enum):
589@typing.final
590class ItemSubType(int, Enum):
591    """An enum for Destiny 2 inventory items subtype."""
592
593    NONE = 0
594    AUTORIFLE = 6
595    SHOTGUN = 7
596    MACHINEGUN = 8
597    HANDCANNON = 9
598    ROCKETLAUNCHER = 10
599    FUSIONRIFLE = 11
600    SNIPERRIFLE = 12
601    PULSERIFLE = 13
602    SCOUTRIFLE = 14
603    SIDEARM = 17
604    SWORD = 18
605    MASK = 19
606    SHADER = 20
607    ORNAMENT = 21
608    FUSIONRIFLELINE = 22
609    GRENADELAUNCHER = 23
610    SUBMACHINEGUN = 24
611    TRACERIFLE = 25
612    HELMETARMOR = 26
613    GAUNTLETSARMOR = 27
614    CHESTARMOR = 28
615    LEGARMOR = 29
616    CLASSARMOR = 30
617    BOW = 31
618    DUMMYREPEATABLEBOUNTY = 32

An enum for Destiny 2 inventory items subtype.

NONE = <ItemSubType.NONE: 0>
AUTORIFLE = <ItemSubType.AUTORIFLE: 6>
SHOTGUN = <ItemSubType.SHOTGUN: 7>
MACHINEGUN = <ItemSubType.MACHINEGUN: 8>
HANDCANNON = <ItemSubType.HANDCANNON: 9>
ROCKETLAUNCHER = <ItemSubType.ROCKETLAUNCHER: 10>
FUSIONRIFLE = <ItemSubType.FUSIONRIFLE: 11>
SNIPERRIFLE = <ItemSubType.SNIPERRIFLE: 12>
PULSERIFLE = <ItemSubType.PULSERIFLE: 13>
SCOUTRIFLE = <ItemSubType.SCOUTRIFLE: 14>
SIDEARM = <ItemSubType.SIDEARM: 17>
SWORD = <ItemSubType.SWORD: 18>
MASK = <ItemSubType.MASK: 19>
SHADER = <ItemSubType.SHADER: 20>
ORNAMENT = <ItemSubType.ORNAMENT: 21>
FUSIONRIFLELINE = <ItemSubType.FUSIONRIFLELINE: 22>
GRENADELAUNCHER = <ItemSubType.GRENADELAUNCHER: 23>
SUBMACHINEGUN = <ItemSubType.SUBMACHINEGUN: 24>
TRACERIFLE = <ItemSubType.TRACERIFLE: 25>
HELMETARMOR = <ItemSubType.HELMETARMOR: 26>
GAUNTLETSARMOR = <ItemSubType.GAUNTLETSARMOR: 27>
CHESTARMOR = <ItemSubType.CHESTARMOR: 28>
LEGARMOR = <ItemSubType.LEGARMOR: 29>
CLASSARMOR = <ItemSubType.CLASSARMOR: 30>
BOW = <ItemSubType.BOW: 31>
DUMMYREPEATABLEBOUNTY = <ItemSubType.DUMMYREPEATABLEBOUNTY: 32>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemTier(builtins.int, aiobungie.Enum):
621@typing.final
622class ItemTier(int, Enum):
623    """An enum for a Destiny 2 item tier."""
624
625    NONE = 0
626    BASIC = 3340296461
627    COMMON = 2395677314
628    RARE = 2127292149
629    LEGENDERY = 4008398120
630    EXOTIC = 2759499571

An enum for a Destiny 2 item tier.

NONE = <ItemTier.NONE: 0>
BASIC = <ItemTier.BASIC: 3340296461>
COMMON = <ItemTier.COMMON: 2395677314>
RARE = <ItemTier.RARE: 2127292149>
LEGENDERY = <ItemTier.LEGENDERY: 4008398120>
EXOTIC = <ItemTier.EXOTIC: 2759499571>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class ItemType(builtins.int, aiobungie.Enum):
556@typing.final
557class ItemType(int, Enum):
558    """Enums for Destiny2's item types."""
559
560    NONE = 0
561    CURRENCY = 1
562    ARMOR = 2
563    WEAPON = 3
564    MESSAGE = 7
565    ENGRAM = 8
566    CONSUMABLE = 9
567    EXCHANGEMATERIAL = 10
568    MISSIONREWARD = 11
569    QUESTSTEP = 12
570    QUESTSTEPCOMPLETE = 13
571    EMBLEM = 14
572    QUEST = 15
573    SUBCLASS = 16
574    CLANBANNER = 17
575    AURA = 18
576    MOD = 19
577    DUMMY = 20
578    SHIP = 21
579    VEHICLE = 22
580    EMOTE = 23
581    GHOST = 24
582    PACKAGE = 25
583    BOUNTY = 26
584    WRAPPER = 27
585    SEASONALARTIFACT = 28
586    FINISHER = 29

Enums for Destiny2's item types.

NONE = <ItemType.NONE: 0>
CURRENCY = <ItemType.CURRENCY: 1>
ARMOR = <ItemType.ARMOR: 2>
WEAPON = <ItemType.WEAPON: 3>
MESSAGE = <ItemType.MESSAGE: 7>
ENGRAM = <ItemType.ENGRAM: 8>
CONSUMABLE = <ItemType.CONSUMABLE: 9>
EXCHANGEMATERIAL = <ItemType.EXCHANGEMATERIAL: 10>
MISSIONREWARD = <ItemType.MISSIONREWARD: 11>
QUESTSTEP = <ItemType.QUESTSTEP: 12>
QUESTSTEPCOMPLETE = <ItemType.QUESTSTEPCOMPLETE: 13>
EMBLEM = <ItemType.EMBLEM: 14>
QUEST = <ItemType.QUEST: 15>
SUBCLASS = <ItemType.SUBCLASS: 16>
CLANBANNER = <ItemType.CLANBANNER: 17>
AURA = <ItemType.AURA: 18>
MOD = <ItemType.MOD: 19>
DUMMY = <ItemType.DUMMY: 20>
SHIP = <ItemType.SHIP: 21>
VEHICLE = <ItemType.VEHICLE: 22>
EMOTE = <ItemType.EMOTE: 23>
GHOST = <ItemType.GHOST: 24>
PACKAGE = <ItemType.PACKAGE: 25>
BOUNTY = <ItemType.BOUNTY: 26>
WRAPPER = <ItemType.WRAPPER: 27>
SEASONALARTIFACT = <ItemType.SEASONALARTIFACT: 28>
FINISHER = <ItemType.FINISHER: 29>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipOption(builtins.int, aiobungie.Enum):
713@typing.final
714class MembershipOption(int, Enum):
715    """A enum for GroupV2 membership options."""
716
717    REVIEWD = 0
718    OPEN = 1
719    CLOSED = 2

A enum for GroupV2 membership options.

REVIEWD = <MembershipOption.REVIEWD: 0>
OPEN = <MembershipOption.OPEN: 1>
CLOSED = <MembershipOption.CLOSED: 2>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class MembershipType(builtins.int, aiobungie.Enum):
463@typing.final
464class MembershipType(int, Enum):
465    """An Enum for Bungie membership types."""
466
467    NONE = 0
468    XBOX = 1
469    PSN = 2
470    STEAM = 3
471    BLIZZARD = 4
472    STADIA = 5
473    BUNGIE = 254
474    ALL = -1

An Enum for Bungie membership types.

NONE = <MembershipType.NONE: 0>
XBOX = <MembershipType.XBOX: 1>
PSN = <MembershipType.PSN: 2>
STEAM = <MembershipType.STEAM: 3>
BLIZZARD = <MembershipType.BLIZZARD: 4>
STADIA = <MembershipType.STADIA: 5>
BUNGIE = <MembershipType.BUNGIE: 254>
ALL = <MembershipType.ALL: -1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class MembershipTypeError(aiobungie.BadRequest):
176@attrs.define(auto_exc=True)
177class MembershipTypeError(BadRequest):
178    """A bad request error raised when passing wrong membership to the request.
179
180    Those fields are useful since it returns the correct membership and id which can be used
181    to make the request again with those fields.
182    """
183
184    membership_type: str = attrs.field(default="")
185    """The errored membership type passed to the request."""
186
187    membership_id: int = attrs.field(default=0)
188    """The errored user's membership id."""
189
190    required_membership: str = attrs.field(default="")
191    """The required correct membership for errored user."""
192
193    def __str__(self) -> str:
194        return (
195            f"Expected membership: {self.required_membership}, "
196            f"But got {self.membership_type} for id {self.membership_id}"
197        )
198
199    def __int__(self) -> int:
200        return int(self.membership_id)

A bad request error raised when passing wrong membership to the request.

Those fields are useful since it returns the correct membership and id which can be used to make the request again with those fields.

MembershipTypeError( message: str, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], http_status: http.HTTPStatus = <HTTPStatus.BAD_REQUEST: 400>, membership_type: str = '', membership_id: int = 0, required_membership: str = '')
 2def __init__(self, message, url, body, headers, http_status=attr_dict['http_status'].default, membership_type=attr_dict['membership_type'].default, membership_id=attr_dict['membership_id'].default, required_membership=attr_dict['required_membership'].default):
 3    self.message = message
 4    self.url = url
 5    self.body = body
 6    self.headers = headers
 7    self.http_status = http_status
 8    self.membership_type = membership_type
 9    self.membership_id = membership_id
10    self.required_membership = required_membership
11    BaseException.__init__(self, self.message,self.url,self.body,self.headers,self.http_status,self.membership_type,self.membership_id,self.required_membership)

Method generated by attrs for class MembershipTypeError.

membership_type: str

The errored membership type passed to the request.

membership_id: int

The errored user's membership id.

required_membership: str

The required correct membership for errored user.

Inherited Members
BadRequest
url
body
headers
http_status
HTTPError
message
builtins.BaseException
with_traceback
args
@typing.final
class MilestoneType(builtins.int, aiobungie.Enum):
506@typing.final
507class MilestoneType(int, Enum):
508    """An Enum for Destiny 2 milestone types."""
509
510    UNKNOWN = 0
511    TUTORIAL = 1
512    ONETIME = 2
513    WEEKLY = 3
514    DAILY = 4
515    SPECIAL = 5

An Enum for Destiny 2 milestone types.

UNKNOWN = <MilestoneType.UNKNOWN: 0>
TUTORIAL = <MilestoneType.TUTORIAL: 1>
ONETIME = <MilestoneType.ONETIME: 2>
WEEKLY = <MilestoneType.WEEKLY: 3>
DAILY = <MilestoneType.DAILY: 4>
SPECIAL = <MilestoneType.SPECIAL: 5>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class NotFound(aiobungie.HTTPException):
142@attrs.define(auto_exc=True)
143class NotFound(HTTPException):
144    """Raised when an unknown request was not found."""
145
146    http_status: http.HTTPStatus = attrs.field(
147        default=http.HTTPStatus.NOT_FOUND, init=False
148    )

Raised when an unknown request was not found.

NotFound( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class NotFound.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class ObjectiveUIStyle(builtins.int, aiobungie.Enum):
 94@typing.final
 95class ObjectiveUIStyle(int, enums.Enum):
 96    NONE = 0
 97    HIGHLIGHTED = 1
 98    CRAFTING_WEAPON_LEVEL = 2
 99    CRAFTING_WEAPON_LEVEL_PROGRESS = 3
100    CRAFTING_WEAPON_TIMESTAMP = 4
101    CRAFTING_MEMENTOS = 5
102    CRAFTING_MEMENTO_TITLE = 6

An enumeration.

NONE = <ObjectiveUIStyle.NONE: 0>
HIGHLIGHTED = <ObjectiveUIStyle.HIGHLIGHTED: 1>
CRAFTING_WEAPON_LEVEL = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL: 2>
CRAFTING_WEAPON_LEVEL_PROGRESS = <ObjectiveUIStyle.CRAFTING_WEAPON_LEVEL_PROGRESS: 3>
CRAFTING_WEAPON_TIMESTAMP = <ObjectiveUIStyle.CRAFTING_WEAPON_TIMESTAMP: 4>
CRAFTING_MEMENTOS = <ObjectiveUIStyle.CRAFTING_MEMENTOS: 5>
CRAFTING_MEMENTO_TITLE = <ObjectiveUIStyle.CRAFTING_MEMENTO_TITLE: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Place(builtins.int, aiobungie.Enum):
235@typing.final
236class Place(int, Enum):
237    """An Enum for Destiny 2 Places and NOT Planets"""
238
239    ORBIT = 2961497387
240    SOCIAL = 4151112093
241    LIGHT_HOUSE = 4276116472
242    EXPLORE = 3497767639

An Enum for Destiny 2 Places and NOT Planets

ORBIT = <Place.ORBIT: 2961497387>
SOCIAL = <Place.SOCIAL: 4151112093>
LIGHT_HOUSE = <Place.LIGHT_HOUSE: 4276116472>
EXPLORE = <Place.EXPLORE: 3497767639>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Planet(builtins.int, aiobungie.Enum):
200@typing.final
201class Planet(int, Enum):
202    """An Enum for all available planets in Destiny 2."""
203
204    UNKNOWN = 0
205    """Unknown space"""
206
207    EARTH = 3747705955
208    """Earth"""
209
210    DREAMING_CITY = 2877881518
211    """The Dreaming city."""
212
213    NESSUS = 3526908984
214    """Nessus"""
215
216    MOON = 3325508439
217    """The Moon"""
218
219    COSMODROME = 3990611421
220    """The Cosmodrome"""
221
222    TANGLED_SHORE = 3821439926
223    """The Tangled Shore"""
224
225    VENUS = 3871070152
226    """Venus"""
227
228    EAZ = 541863059  # Exclusive event.
229    """European Aerial Zone"""
230
231    EUROPA = 1729879943
232    """Europa"""

An Enum for all available planets in Destiny 2.

UNKNOWN = <Planet.UNKNOWN: 0>

Unknown space

EARTH = <Planet.EARTH: 3747705955>

Earth

DREAMING_CITY = <Planet.DREAMING_CITY: 2877881518>

The Dreaming city.

NESSUS = <Planet.NESSUS: 3526908984>

Nessus

MOON = <Planet.MOON: 3325508439>

The Moon

COSMODROME = <Planet.COSMODROME: 3990611421>

The Cosmodrome

TANGLED_SHORE = <Planet.TANGLED_SHORE: 3821439926>

The Tangled Shore

VENUS = <Planet.VENUS: 3871070152>

Venus

EAZ = <Planet.EAZ: 541863059>

European Aerial Zone

EUROPA = <Planet.EUROPA: 1729879943>

Europa

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Presence(builtins.int, aiobungie.Enum):
683@typing.final
684class Presence(int, Enum):
685    """An enum for a bungie friend status."""
686
687    OFFLINE_OR_UNKNOWN = 0
688    ONLINE = 1

An enum for a bungie friend status.

OFFLINE_OR_UNKNOWN = <Presence.OFFLINE_OR_UNKNOWN: 0>
ONLINE = <Presence.ONLINE: 1>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class PrivacySetting(builtins.int, aiobungie.Enum):
771@typing.final
772class PrivacySetting(int, Enum):
773    """An enum for players's privacy settings."""
774
775    OPEN = 0
776    CLAN_AND_FRIENDS = 1
777    FRIENDS_ONLY = 2
778    INVITE_ONLY = 3
779    CLOSED = 4

An enum for players's privacy settings.

OPEN = <PrivacySetting.OPEN: 0>
CLAN_AND_FRIENDS = <PrivacySetting.CLAN_AND_FRIENDS: 1>
FRIENDS_ONLY = <PrivacySetting.FRIENDS_ONLY: 2>
INVITE_ONLY = <PrivacySetting.INVITE_ONLY: 3>
CLOSED = <PrivacySetting.CLOSED: 4>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RESTClient(aiobungie.interfaces.rest.RESTInterface):
 350class RESTClient(interfaces.RESTInterface):
 351    """A RESTful client implementation for Bungie's API.
 352
 353    This client is designed to only make HTTP requests and return JSON objects
 354    to provide RESTful functionality.
 355
 356    This client is also used within `aiobungie.Client` which deserialize those returned JSON objects
 357    using the factory into Pythonic data classes objects which provide Python functionality.
 358
 359    Example
 360    -------
 361    ```py
 362    import aiobungie
 363
 364    async def main():
 365        async with aiobungie.RESTClient("TOKEN") as rest_client:
 366            req = await rest_client.fetch_clan_members(4389205)
 367            clan_members = req['results']
 368            for member in clan_members:
 369                for k, v in member['destinyUserInfo'].items():
 370                    print(k, v)
 371    ```
 372
 373    Parameters
 374    ----------
 375    token : `str`
 376        A valid application token from Bungie's developer portal.
 377
 378    Other Parameters
 379    ----------------
 380    max_retries : `int`
 381        The max retries number to retry if the request hit a `5xx` status code.
 382    max_ratelimit_retries : `int`
 383        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
 384    client_secret : `typing.Optional[str]`
 385        An optional application client secret,
 386        This is only needed if you're fetching OAuth2 tokens with this client.
 387    client_id : `typing.Optional[int]`
 388        An optional application client id,
 389        This is only needed if you're fetching OAuth2 tokens with this client.
 390    enable_debugging : `bool | str`
 391        Whether to enable logging responses or not.
 392
 393    Logging Levels
 394    --------------
 395    * `False`: This will disable logging.
 396    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
 397    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
 398    """
 399
 400    __slots__ = (
 401        "_token",
 402        "_session",
 403        "_lock",
 404        "_max_retries",
 405        "_client_secret",
 406        "_client_id",
 407        "_metadata",
 408        "_max_rate_limit_retries",
 409    )
 410
 411    def __init__(
 412        self,
 413        token: str,
 414        /,
 415        client_secret: typing.Optional[str] = None,
 416        client_id: typing.Optional[int] = None,
 417        *,
 418        max_retries: int = 4,
 419        max_ratelimit_retries: int = 3,
 420        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 421    ) -> None:
 422        self._session: typing.Optional[_Session] = None
 423        self._lock: typing.Optional[asyncio.Lock] = None
 424        self._client_secret = client_secret
 425        self._client_id = client_id
 426        self._token: str = token
 427        self._max_retries = max_retries
 428        self._max_rate_limit_retries = max_ratelimit_retries
 429        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
 430
 431        self._set_debug_level(enable_debugging)
 432
 433    @property
 434    def client_id(self) -> typing.Optional[int]:
 435        return self._client_id
 436
 437    @property
 438    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
 439        return self._metadata
 440
 441    @property
 442    def is_alive(self) -> bool:
 443        return self._session is not None
 444
 445    @typing.final
 446    async def close(self) -> None:
 447        if self._session is not None:
 448            await self._session.close()
 449            self._session = None
 450
 451    @typing.final
 452    def enable_debugging(
 453        self,
 454        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 455        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 456        /,
 457    ) -> None:
 458        self._set_debug_level(level, file)
 459
 460    @typing.final
 461    async def static_request(
 462        self,
 463        method: typing.Union[RequestMethod, str],
 464        path: str,
 465        *,
 466        auth: typing.Optional[str] = None,
 467        json: typing.Optional[dict[str, typing.Any]] = None,
 468    ) -> ResponseSig:
 469        return await self._request(method, path, auth=auth, json=json)
 470
 471    @typing.final
 472    def build_oauth2_url(
 473        self, client_id: typing.Optional[int] = None
 474    ) -> typing.Optional[str]:
 475        client_id = client_id or self._client_id
 476        if client_id is None:
 477            return None
 478
 479        return url.OAUTH2_EP_BUILDER.format(
 480            oauth_endpoint=url.OAUTH_EP,
 481            client_id=client_id,
 482            uuid=_uuid(),
 483        )
 484
 485    def _open(self) -> _Session:
 486        """Open a new client session. This is called internally with contextmanager usage."""
 487        asyncio.get_running_loop()
 488        if self._session is None:
 489            self._session = _Session.create(
 490                owner=False,
 491                raise_status=False,
 492                connect=None,
 493                socket_read=None,
 494                socket_connect=None,
 495            )
 496        return self._session
 497
 498    @staticmethod
 499    def _set_debug_level(
 500        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
 501        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
 502    ) -> None:
 503
 504        file_handler = logging.FileHandler(file, mode="w") if file else None
 505        if level == "TRACE" or level == TRACE:
 506            logging.basicConfig(
 507                level=TRACE, handlers=[file_handler] if file_handler else None
 508            )
 509
 510        elif level:
 511            logging.basicConfig(
 512                level=logging.DEBUG, handlers=[file_handler] if file_handler else None
 513            )
 514
 515    async def _request(
 516        self,
 517        method: typing.Union[RequestMethod, str],
 518        route: str,
 519        *,
 520        base: bool = False,
 521        oauth2: bool = False,
 522        auth: typing.Optional[str] = None,
 523        unwrapping: typing.Literal["json", "read"] = "json",
 524        json: typing.Optional[dict[str, typing.Any]] = None,
 525        headers: typing.Optional[dict[str, typing.Any]] = None,
 526        data: typing.Optional[typing.Union[str, dict[str, typing.Any]]] = None,
 527    ) -> ResponseSig:
 528
 529        retries: int = 0
 530        session = self._open()
 531        headers = headers or {}
 532
 533        headers.setdefault(_USER_AGENT_HEADERS, _USER_AGENT)
 534        headers["X-API-KEY"] = self._token
 535
 536        if auth is not None:
 537            headers[_AUTH_HEADER] = f"Bearer {auth}"
 538
 539        # Handling endpoints
 540        endpoint = url.BASE
 541
 542        if not base:
 543            endpoint = endpoint + url.REST_EP
 544
 545        if oauth2:
 546            headers["Content-Type"] = "application/x-www-form-urlencoded"
 547            endpoint = endpoint + url.TOKEN_EP
 548
 549        if self._lock is None:
 550            self._lock = asyncio.Lock()
 551
 552        while True:
 553            try:
 554                async with (stack := contextlib.AsyncExitStack()):
 555                    await stack.enter_async_context(self._lock)
 556
 557                    # We make the request here.
 558                    taken_time = time.monotonic()
 559                    response = await stack.enter_async_context(
 560                        session.client_session.request(
 561                            method=method,
 562                            url=f"{endpoint}/{route}",
 563                            json=json,
 564                            headers=headers,
 565                            data=data,
 566                        )
 567                    )
 568                    response_time = (time.monotonic() - taken_time) * 1_000
 569
 570                    _LOG.debug(
 571                        "%s %s %s Time %.4fms",
 572                        method,
 573                        f"{endpoint}/{route}",
 574                        f"{response.status} {response.reason}",
 575                        response_time,
 576                    )
 577
 578                    await self._handle_ratelimit(
 579                        response, method, route, self._max_rate_limit_retries
 580                    )
 581
 582                    if response.status == http.HTTPStatus.NO_CONTENT:
 583                        return None
 584
 585                    if 300 > response.status >= 200:
 586                        if unwrapping == "read":
 587                            # We need to read the bytes for the manifest response.
 588                            return await response.read()
 589
 590                        if response.content_type == _APP_JSON:
 591                            json_data = await response.json()
 592
 593                            _LOG.debug(
 594                                "%s %s %s Time %.4fms",
 595                                method,
 596                                f"{endpoint}/{route}",
 597                                f"{response.status} {response.reason}",
 598                                response_time,
 599                            )
 600
 601                            if _LOG.isEnabledFor(TRACE):
 602                                headers.update(response.headers)
 603
 604                                _LOG.log(
 605                                    TRACE,
 606                                    "%s",
 607                                    error.stringify_http_message(headers),
 608                                )
 609
 610                            # Return the response.
 611                            # oauth2 responses are not packed inside a Response object.
 612                            if oauth2:
 613                                return json_data  # type: ignore[no-any-return]
 614
 615                            return json_data["Response"]  # type: ignore[no-any-return]
 616
 617                    if (
 618                        response.status in _RETRY_5XX
 619                        and retries < self._max_retries  # noqa: W503
 620                    ):
 621                        backoff_ = backoff.ExponentialBackOff(maximum=6)
 622                        sleep_time = next(backoff_)
 623                        _LOG.warning(
 624                            "Got %i - %s. Sleeping for %.2f seconds. Remaining retries: %i",
 625                            response.status,
 626                            response.reason,
 627                            sleep_time,
 628                            self._max_retries - retries,
 629                        )
 630
 631                        retries += 1
 632                        await asyncio.sleep(sleep_time)
 633                        continue
 634
 635                    raise await error.raise_error(response)
 636            # eol
 637            except _Dyn:
 638                continue
 639
 640    if not typing.TYPE_CHECKING:
 641
 642        def __enter__(self) -> typing.NoReturn:
 643            cls = type(self)
 644            raise TypeError(
 645                f"{cls.__qualname__} is async only, use 'async with' instead."
 646            )
 647
 648        def __exit__(
 649            self,
 650            exception_type: typing.Optional[type[BaseException]],
 651            exception: typing.Optional[BaseException],
 652            exception_traceback: typing.Optional[types.TracebackType],
 653        ) -> None:
 654            ...
 655
 656    async def __aenter__(self) -> RESTClient:
 657        self._open()
 658        return self
 659
 660    async def __aexit__(
 661        self,
 662        exception_type: typing.Optional[type[BaseException]],
 663        exception: typing.Optional[BaseException],
 664        exception_traceback: typing.Optional[types.TracebackType],
 665    ) -> None:
 666        await self.close()
 667
 668    # We don't want this to be super complicated.
 669    @staticmethod
 670    @typing.final
 671    async def _handle_ratelimit(
 672        response: aiohttp.ClientResponse,
 673        method: str,
 674        route: str,
 675        max_ratelimit_retries: int = 3,
 676    ) -> None:
 677
 678        if response.status != http.HTTPStatus.TOO_MANY_REQUESTS:
 679            return
 680
 681        if response.content_type != _APP_JSON:
 682            raise error.HTTPError(
 683                f"Being ratelimited on non JSON request, {response.content_type}.",
 684                http.HTTPStatus.TOO_MANY_REQUESTS,
 685            )
 686
 687        count: int = 0
 688        json: typedefs.JSONObject = await response.json()
 689        retry_after = float(json["ThrottleSeconds"])
 690
 691        while True:
 692            if count == max_ratelimit_retries:
 693                raise _Dyn
 694
 695            if retry_after <= 0:
 696                # We sleep for a little bit to avoid funky behavior.
 697                sleep_time = float(random.random() + 0.93) / 2
 698
 699                _LOG.warning(
 700                    "We're being ratelimited with method %s route %s. Sleeping for %.2fs.",
 701                    method,
 702                    route,
 703                    sleep_time,
 704                )
 705                count += 1
 706                await asyncio.sleep(sleep_time)
 707                continue
 708
 709            raise error.RateLimitedError(
 710                body=json,
 711                url=str(response.real_url),
 712                retry_after=retry_after,
 713            )
 714
 715    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
 716
 717        if not isinstance(self._client_id, int):
 718            raise TypeError(
 719                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 720            )
 721
 722        if not isinstance(self._client_secret, str):
 723            raise TypeError(
 724                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 725            )
 726
 727        headers = {
 728            "client_secret": self._client_secret,
 729        }
 730
 731        data = (
 732            f"grant_type=authorization_code&code={code}"
 733            f"&client_id={self._client_id}&client_secret={self._client_secret}"
 734        )
 735
 736        response = await self._request(
 737            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
 738        )
 739        assert isinstance(response, dict)
 740        return builders.OAuth2Response.build_response(response)
 741
 742    async def refresh_access_token(
 743        self, refresh_token: str, /
 744    ) -> builders.OAuth2Response:
 745        if not isinstance(self._client_id, int):
 746            raise TypeError(
 747                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
 748            )
 749
 750        if not isinstance(self._client_secret, str):
 751            raise TypeError(
 752                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
 753            )
 754
 755        data = {
 756            "grant_type": "refresh_token",
 757            "refresh_token": refresh_token,
 758            "client_id": self._client_id,
 759            "client_secret": self._client_secret,
 760            "Content-Type": "application/x-www-form-urlencoded",
 761        }
 762
 763        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
 764        assert isinstance(response, dict)
 765        return builders.OAuth2Response.build_response(response)
 766
 767    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
 768        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 769        resp = await self._request(
 770            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
 771        )
 772        assert isinstance(resp, dict)
 773        return resp
 774
 775    async def fetch_user_themes(self) -> typedefs.JSONArray:
 776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 777        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
 778        assert isinstance(resp, list)
 779        return resp
 780
 781    async def fetch_membership_from_id(
 782        self,
 783        id: int,
 784        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 785        /,
 786    ) -> typedefs.JSONObject:
 787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 788        resp = await self._request(
 789            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
 790        )
 791        assert isinstance(resp, dict)
 792        return resp
 793
 794    async def fetch_player(
 795        self,
 796        name: str,
 797        code: int,
 798        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
 799        /,
 800    ) -> typedefs.JSONArray:
 801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 802        resp = await self._request(
 803            RequestMethod.POST,
 804            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
 805            json={"displayName": name, "displayNameCode": code},
 806        )
 807        assert isinstance(resp, list)
 808        return resp
 809
 810    async def search_users(self, name: str, /) -> typedefs.JSONObject:
 811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 812        resp = await self._request(
 813            RequestMethod.POST,
 814            "User/Search/GlobalName/0",
 815            json={"displayNamePrefix": name},
 816        )
 817        assert isinstance(resp, dict)
 818        return resp
 819
 820    async def fetch_clan_from_id(
 821        self, id: int, /, access_token: typing.Optional[str] = None
 822    ) -> typedefs.JSONObject:
 823        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 824        resp = await self._request(
 825            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
 826        )
 827        assert isinstance(resp, dict)
 828        return resp
 829
 830    async def fetch_clan(
 831        self,
 832        name: str,
 833        /,
 834        access_token: typing.Optional[str] = None,
 835        *,
 836        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 837    ) -> typedefs.JSONObject:
 838        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 839        resp = await self._request(
 840            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
 841        )
 842        assert isinstance(resp, dict)
 843        return resp
 844
 845    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
 846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 847        resp = await self._request(
 848            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
 849        )
 850        assert isinstance(resp, dict)
 851        return resp
 852
 853    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
 854        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 855        resp = await self._request(
 856            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
 857        )
 858        assert isinstance(resp, list)
 859        return resp
 860
 861    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
 862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 863        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
 864        assert isinstance(resp, dict)
 865        return resp
 866
 867    async def fetch_character(
 868        self,
 869        member_id: int,
 870        membership_type: typedefs.IntAnd[enums.MembershipType],
 871        character_id: int,
 872        components: list[enums.ComponentType],
 873        auth: typing.Optional[str] = None,
 874    ) -> typedefs.JSONObject:
 875        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 876        collector = _collect_components(components)
 877        response = await self._request(
 878            RequestMethod.GET,
 879            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
 880            f"Character/{character_id}/?components={collector}",
 881            auth=auth,
 882        )
 883        assert isinstance(response, dict)
 884        return response
 885
 886    async def fetch_activities(
 887        self,
 888        member_id: int,
 889        character_id: int,
 890        mode: typedefs.IntAnd[enums.GameMode],
 891        membership_type: typedefs.IntAnd[
 892            enums.MembershipType
 893        ] = enums.MembershipType.ALL,
 894        *,
 895        page: int = 0,
 896        limit: int = 1,
 897    ) -> typedefs.JSONObject:
 898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 899        resp = await self._request(
 900            RequestMethod.GET,
 901            f"Destiny2/{int(membership_type)}/Account/"
 902            f"{member_id}/Character/{character_id}/Stats/Activities"
 903            f"/?mode={int(mode)}&count={limit}&page={page}",
 904        )
 905        assert isinstance(resp, dict)
 906        return resp
 907
 908    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
 909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 910        resp = await self._request(
 911            RequestMethod.GET,
 912            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
 913        )
 914        assert isinstance(resp, dict)
 915        return resp
 916
 917    async def fetch_profile(
 918        self,
 919        membership_id: int,
 920        type: typedefs.IntAnd[enums.MembershipType],
 921        components: list[enums.ComponentType],
 922        auth: typing.Optional[str] = None,
 923    ) -> typedefs.JSONObject:
 924        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 925        collector = _collect_components(components)
 926        response = await self._request(
 927            RequestMethod.GET,
 928            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
 929            auth=auth,
 930        )
 931        assert isinstance(response, dict)
 932        return response
 933
 934    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
 935        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 936        response = await self._request(
 937            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
 938        )
 939        assert isinstance(response, dict)
 940        return response
 941
 942    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
 943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 944        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
 945        assert isinstance(resp, dict)
 946        return resp
 947
 948    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
 949        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 950        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
 951        assert isinstance(resp, dict)
 952        return resp
 953
 954    async def fetch_groups_for_member(
 955        self,
 956        member_id: int,
 957        member_type: typedefs.IntAnd[enums.MembershipType],
 958        /,
 959        *,
 960        filter: int = 0,
 961        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 962    ) -> typedefs.JSONObject:
 963        resp = await self._request(
 964            RequestMethod.GET,
 965            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 966        )
 967        assert isinstance(resp, dict)
 968        return resp
 969
 970    async def fetch_potential_groups_for_member(
 971        self,
 972        member_id: int,
 973        member_type: typedefs.IntAnd[enums.MembershipType],
 974        /,
 975        *,
 976        filter: int = 0,
 977        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
 978    ) -> typedefs.JSONObject:
 979        resp = await self._request(
 980            RequestMethod.GET,
 981            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
 982        )
 983        assert isinstance(resp, dict)
 984        return resp
 985
 986    async def fetch_clan_members(
 987        self,
 988        clan_id: int,
 989        /,
 990        *,
 991        name: typing.Optional[str] = None,
 992        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 993    ) -> typedefs.JSONObject:
 994        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 995        resp = await self._request(
 996            RequestMethod.GET,
 997            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 998        )
 999        assert isinstance(resp, dict)
1000        return resp
1001
1002    async def fetch_hardlinked_credentials(
1003        self,
1004        credential: int,
1005        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1006        /,
1007    ) -> typedefs.JSONObject:
1008        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1009        resp = await self._request(
1010            RequestMethod.GET,
1011            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1012        )
1013        assert isinstance(resp, dict)
1014        return resp
1015
1016    async def fetch_user_credentials(
1017        self, access_token: str, membership_id: int, /
1018    ) -> typedefs.JSONArray:
1019        resp = await self._request(
1020            RequestMethod.GET,
1021            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1022            auth=access_token,
1023        )
1024        assert isinstance(resp, list)
1025        return resp
1026
1027    async def insert_socket_plug(
1028        self,
1029        action_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "actionToken": action_token,
1042            "itemInstanceId": instance_id,
1043            "plug": plug,
1044            "characterId": character_id,
1045            "membershipType": int(membership_type),
1046        }
1047        resp = await self._request(
1048            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1049        )
1050        assert isinstance(resp, dict)
1051        return resp
1052
1053    async def insert_socket_plug_free(
1054        self,
1055        access_token: str,
1056        /,
1057        instance_id: int,
1058        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1059        character_id: int,
1060        membership_type: typedefs.IntAnd[enums.MembershipType],
1061    ) -> typedefs.JSONObject:
1062
1063        if isinstance(plug, builders.PlugSocketBuilder):
1064            plug = plug.collect()
1065
1066        body = {
1067            "itemInstanceId": instance_id,
1068            "plug": plug,
1069            "characterId": character_id,
1070            "membershipType": int(membership_type),
1071        }
1072        resp = await self._request(
1073            RequestMethod.POST,
1074            "Destiny2/Actions/Items/InsertSocketPlugFree",
1075            json=body,
1076            auth=access_token,
1077        )
1078        assert isinstance(resp, dict)
1079        return resp
1080
1081    async def set_item_lock_state(
1082        self,
1083        access_token: str,
1084        state: bool,
1085        /,
1086        item_id: int,
1087        character_id: int,
1088        membership_type: typedefs.IntAnd[enums.MembershipType],
1089    ) -> int:
1090        body = {
1091            "state": state,
1092            "itemId": item_id,
1093            "characterId": character_id,
1094            "membership_type": int(membership_type),
1095        }
1096        response = await self._request(
1097            RequestMethod.POST,
1098            "Destiny2/Actions/Items/SetLockState",
1099            json=body,
1100            auth=access_token,
1101        )
1102        assert isinstance(response, int)
1103        return response
1104
1105    async def set_quest_track_state(
1106        self,
1107        access_token: str,
1108        state: bool,
1109        /,
1110        item_id: int,
1111        character_id: int,
1112        membership_type: typedefs.IntAnd[enums.MembershipType],
1113    ) -> int:
1114        body = {
1115            "state": state,
1116            "itemId": item_id,
1117            "characterId": character_id,
1118            "membership_type": int(membership_type),
1119        }
1120        response = await self._request(
1121            RequestMethod.POST,
1122            "Destiny2/Actions/Items/SetTrackedState",
1123            json=body,
1124            auth=access_token,
1125        )
1126        assert isinstance(response, int)
1127        return response
1128
1129    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1130        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1131        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1132        assert isinstance(path, dict)
1133        return path
1134
1135    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1136        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1137        _ensure_manifest_language(language)
1138
1139        content = await self.fetch_manifest_path()
1140        resp = await self._request(
1141            RequestMethod.GET,
1142            content["mobileWorldContentPaths"][language],
1143            unwrapping="read",
1144            base=True,
1145        )
1146        assert isinstance(resp, bytes)
1147        return resp
1148
1149    async def download_manifest(
1150        self,
1151        language: str = "en",
1152        name: str = "manifest.sqlite3",
1153        *,
1154        force: bool = False,
1155    ) -> None:
1156        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1157        if os.path.exists(name):
1158
1159            if force:
1160                _LOG.debug("Forcing manifest download.")
1161                os.remove(name)
1162
1163                return await self.download_manifest(language, name, force=force)
1164
1165            else:
1166                raise FileExistsError(
1167                    "Manifest file already exists, "
1168                    "If you want to force download, set the `force` parameter to `True`."
1169                )
1170
1171        _LOG.debug("Downloading manifest...")
1172        data_bytes = await self.read_manifest_bytes(language)
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_sqlite_bytes, data_bytes, name
1175        )
1176
1177    async def download_json_manifest(self, language: str = "en") -> None:
1178        _ensure_manifest_language(language)
1179
1180        _LOG.debug("Downloading manifest JSON...")
1181
1182        content = await self.fetch_manifest_path()
1183        json_bytes = await self._request(
1184            RequestMethod.GET,
1185            content["jsonWorldContentPaths"][language],
1186            unwrapping="read",
1187            base=True,
1188        )
1189
1190        await asyncio.get_running_loop().run_in_executor(
1191            None, _write_json_bytes, json_bytes
1192        )
1193        _LOG.debug("Finished downloading manifest JSON.")
1194
1195    async def fetch_manifest_version(self) -> str:
1196        return typing.cast(str, (await self.fetch_manifest_path())["version"])
1197
1198    @staticmethod
1199    @helpers.deprecated(
1200        since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect"
1201    )
1202    def connect_manifest(
1203        path: typing.Optional[pathlib.Path] = None,
1204        connection: type[sqlite3.Connection] = sqlite3.Connection,
1205    ) -> sqlite3.Connection:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        path = path or pathlib.Path("./manifest.sqlite3")
1208        if not path.exists():
1209            raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.")
1210        return connection(path.name)
1211
1212    async def fetch_linked_profiles(
1213        self,
1214        member_id: int,
1215        member_type: typedefs.IntAnd[enums.MembershipType],
1216        /,
1217        *,
1218        all: bool = False,
1219    ) -> typedefs.JSONObject:
1220        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1221        resp = await self._request(
1222            RequestMethod.GET,
1223            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1224        )
1225        assert isinstance(resp, dict)
1226        return resp
1227
1228    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1229        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1230        resp = await self._request(
1231            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1232        )
1233        assert isinstance(resp, dict)
1234        return resp
1235
1236    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1237        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1238        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1239        assert isinstance(resp, dict)
1240        return resp
1241
1242    async def fetch_public_milestone_content(
1243        self, milestone_hash: int, /
1244    ) -> typedefs.JSONObject:
1245        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1246        resp = await self._request(
1247            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1248        )
1249        assert isinstance(resp, dict)
1250        return resp
1251
1252    async def fetch_current_user_memberships(
1253        self, access_token: str, /
1254    ) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(
1257            RequestMethod.GET,
1258            "User/GetMembershipsForCurrentUser/",
1259            auth=access_token,
1260        )
1261        assert isinstance(resp, dict)
1262        return resp
1263
1264    async def equip_item(
1265        self,
1266        access_token: str,
1267        /,
1268        item_id: int,
1269        character_id: int,
1270        membership_type: typedefs.IntAnd[enums.MembershipType],
1271    ) -> None:
1272        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1273        payload = {
1274            "itemId": item_id,
1275            "characterId": character_id,
1276            "membershipType": int(membership_type),
1277        }
1278
1279        await self._request(
1280            RequestMethod.POST,
1281            "Destiny2/Actions/Items/EquipItem/",
1282            json=payload,
1283            auth=access_token,
1284        )
1285
1286    async def equip_items(
1287        self,
1288        access_token: str,
1289        /,
1290        item_ids: list[int],
1291        character_id: int,
1292        membership_type: typedefs.IntAnd[enums.MembershipType],
1293    ) -> None:
1294        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1295        payload = {
1296            "itemIds": item_ids,
1297            "characterId": character_id,
1298            "membershipType": int(membership_type),
1299        }
1300        await self._request(
1301            RequestMethod.POST,
1302            "Destiny2/Actions/Items/EquipItems/",
1303            json=payload,
1304            auth=access_token,
1305        )
1306
1307    async def ban_clan_member(
1308        self,
1309        access_token: str,
1310        /,
1311        group_id: int,
1312        membership_id: int,
1313        membership_type: typedefs.IntAnd[enums.MembershipType],
1314        *,
1315        length: int = 0,
1316        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1317    ) -> None:
1318        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1319        payload = {"comment": str(comment), "length": length}
1320        await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1323            json=payload,
1324            auth=access_token,
1325        )
1326
1327    async def unban_clan_member(
1328        self,
1329        access_token: str,
1330        /,
1331        group_id: int,
1332        membership_id: int,
1333        membership_type: typedefs.IntAnd[enums.MembershipType],
1334    ) -> None:
1335        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1336        await self._request(
1337            RequestMethod.POST,
1338            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1339            auth=access_token,
1340        )
1341
1342    async def kick_clan_member(
1343        self,
1344        access_token: str,
1345        /,
1346        group_id: int,
1347        membership_id: int,
1348        membership_type: typedefs.IntAnd[enums.MembershipType],
1349    ) -> typedefs.JSONObject:
1350        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1351        resp = await self._request(
1352            RequestMethod.POST,
1353            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1354            auth=access_token,
1355        )
1356        assert isinstance(resp, dict)
1357        return resp
1358
1359    async def edit_clan(
1360        self,
1361        access_token: str,
1362        /,
1363        group_id: int,
1364        *,
1365        name: typedefs.NoneOr[str] = None,
1366        about: typedefs.NoneOr[str] = None,
1367        motto: typedefs.NoneOr[str] = None,
1368        theme: typedefs.NoneOr[str] = None,
1369        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1370        is_public: typedefs.NoneOr[bool] = None,
1371        locale: typedefs.NoneOr[str] = None,
1372        avatar_image_index: typedefs.NoneOr[int] = None,
1373        membership_option: typedefs.NoneOr[
1374            typedefs.IntAnd[enums.MembershipOption]
1375        ] = None,
1376        allow_chat: typedefs.NoneOr[bool] = None,
1377        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1378        call_sign: typedefs.NoneOr[str] = None,
1379        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1380        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1381        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1382        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1383    ) -> None:
1384        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1385        payload = {
1386            "name": name,
1387            "about": about,
1388            "motto": motto,
1389            "theme": theme,
1390            "tags": tags,
1391            "isPublic": is_public,
1392            "avatarImageIndex": avatar_image_index,
1393            "isPublicTopicAdminOnly": is_public_topic_admin,
1394            "allowChat": allow_chat,
1395            "chatSecurity": chat_security,
1396            "callsign": call_sign,
1397            "homepage": homepage,
1398            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1399            "defaultPublicity": default_publicity,
1400            "locale": locale,
1401        }
1402        if membership_option is not None:
1403            payload["membershipOption"] = int(membership_option)
1404
1405        await self._request(
1406            RequestMethod.POST,
1407            f"GroupV2/{group_id}/Edit",
1408            json=payload,
1409            auth=access_token,
1410        )
1411
1412    async def edit_clan_options(
1413        self,
1414        access_token: str,
1415        /,
1416        group_id: int,
1417        *,
1418        invite_permissions_override: typedefs.NoneOr[bool] = None,
1419        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1420        host_guided_game_permission_override: typedefs.NoneOr[
1421            typing.Literal[0, 1, 2]
1422        ] = None,
1423        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1424        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1425    ) -> None:
1426
1427        payload = {
1428            "InvitePermissionOverride": invite_permissions_override,
1429            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1430            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1431            "UpdateBannerPermissionOverride": update_banner_permission_override,
1432            "JoinLevel": int(join_level) if join_level else None,
1433        }
1434
1435        await self._request(
1436            RequestMethod.POST,
1437            f"GroupV2/{group_id}/EditFounderOptions",
1438            json=payload,
1439            auth=access_token,
1440        )
1441
1442    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1443        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1444        resp = await self._request(
1445            RequestMethod.GET,
1446            "Social/Friends/",
1447            auth=access_token,
1448        )
1449        assert isinstance(resp, dict)
1450        return resp
1451
1452    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1453        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1454        resp = await self._request(
1455            RequestMethod.GET,
1456            "Social/Friends/Requests",
1457            auth=access_token,
1458        )
1459        assert isinstance(resp, dict)
1460        return resp
1461
1462    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1463        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1464        await self._request(
1465            RequestMethod.POST,
1466            f"Social/Friends/Requests/Accept/{member_id}",
1467            auth=access_token,
1468        )
1469
1470    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        await self._request(
1473            RequestMethod.POST,
1474            f"Social/Friends/Add/{member_id}",
1475            auth=access_token,
1476        )
1477
1478    async def decline_friend_request(
1479        self, access_token: str, /, member_id: int
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Decline/{member_id}",
1485            auth=access_token,
1486        )
1487
1488    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Remove/{member_id}",
1493            auth=access_token,
1494        )
1495
1496    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        await self._request(
1499            RequestMethod.POST,
1500            f"Social/Friends/Requests/Remove/{member_id}",
1501            auth=access_token,
1502        )
1503
1504    async def approve_all_pending_group_users(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        message: undefined.UndefinedOr[str] = undefined.Undefined,
1510    ) -> None:
1511        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1512        await self._request(
1513            RequestMethod.POST,
1514            f"GroupV2/{group_id}/Members/ApproveAll",
1515            auth=access_token,
1516            json={"message": str(message)},
1517        )
1518
1519    async def deny_all_pending_group_users(
1520        self,
1521        access_token: str,
1522        /,
1523        group_id: int,
1524        *,
1525        message: undefined.UndefinedOr[str] = undefined.Undefined,
1526    ) -> None:
1527        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1528        await self._request(
1529            RequestMethod.POST,
1530            f"GroupV2/{group_id}/Members/DenyAll",
1531            auth=access_token,
1532            json={"message": str(message)},
1533        )
1534
1535    async def add_optional_conversation(
1536        self,
1537        access_token: str,
1538        /,
1539        group_id: int,
1540        *,
1541        name: undefined.UndefinedOr[str] = undefined.Undefined,
1542        security: typing.Literal[0, 1] = 0,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {"chatName": str(name), "chatSecurity": security}
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/OptionalConversations/Add",
1549            json=payload,
1550            auth=access_token,
1551        )
1552
1553    async def edit_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        conversation_id: int,
1559        *,
1560        name: undefined.UndefinedOr[str] = undefined.Undefined,
1561        security: typing.Literal[0, 1] = 0,
1562        enable_chat: bool = False,
1563    ) -> None:
1564        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1565        payload = {
1566            "chatEnabled": enable_chat,
1567            "chatName": str(name),
1568            "chatSecurity": security,
1569        }
1570        await self._request(
1571            RequestMethod.POST,
1572            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1573            json=payload,
1574            auth=access_token,
1575        )
1576
1577    async def transfer_item(
1578        self,
1579        access_token: str,
1580        /,
1581        item_id: int,
1582        item_hash: int,
1583        character_id: int,
1584        member_type: typedefs.IntAnd[enums.MembershipType],
1585        *,
1586        stack_size: int = 1,
1587        vault: bool = False,
1588    ) -> None:
1589        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1590        payload = {
1591            "characterId": character_id,
1592            "membershipType": int(member_type),
1593            "itemId": item_id,
1594            "itemReferenceHash": item_hash,
1595            "stackSize": stack_size,
1596            "transferToVault": vault,
1597        }
1598        await self._request(
1599            RequestMethod.POST,
1600            "Destiny2/Actions/Items/TransferItem",
1601            json=payload,
1602            auth=access_token,
1603        )
1604
1605    async def pull_item(
1606        self,
1607        access_token: str,
1608        /,
1609        item_id: int,
1610        item_hash: int,
1611        character_id: int,
1612        member_type: typedefs.IntAnd[enums.MembershipType],
1613        *,
1614        stack_size: int = 1,
1615        vault: bool = False,
1616    ) -> None:
1617        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1618        payload = {
1619            "characterId": character_id,
1620            "membershipType": int(member_type),
1621            "itemId": item_id,
1622            "itemReferenceHash": item_hash,
1623            "stackSize": stack_size,
1624            "transferToVault": vault,
1625        }
1626        await self._request(
1627            RequestMethod.POST,
1628            "Destiny2/Actions/Items/PullFromPostmaster",
1629            json=payload,
1630            auth=access_token,
1631        )
1632
1633    async def fetch_fireteams(
1634        self,
1635        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1636        *,
1637        platform: typedefs.IntAnd[
1638            fireteams.FireteamPlatform
1639        ] = fireteams.FireteamPlatform.ANY,
1640        language: typing.Union[
1641            fireteams.FireteamLanguage, str
1642        ] = fireteams.FireteamLanguage.ALL,
1643        date_range: typedefs.IntAnd[
1644            fireteams.FireteamDate
1645        ] = fireteams.FireteamDate.ALL,
1646        page: int = 0,
1647        slots_filter: int = 0,
1648    ) -> typedefs.JSONObject:
1649        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1650        resp = await self._request(
1651            RequestMethod.GET,
1652            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1653        )
1654        assert isinstance(resp, dict)
1655        return resp
1656
1657    async def fetch_avaliable_clan_fireteams(
1658        self,
1659        access_token: str,
1660        group_id: int,
1661        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1662        *,
1663        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1664        language: typing.Union[fireteams.FireteamLanguage, str],
1665        date_range: typedefs.IntAnd[
1666            fireteams.FireteamDate
1667        ] = fireteams.FireteamDate.ALL,
1668        page: int = 0,
1669        public_only: bool = False,
1670        slots_filter: int = 0,
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1676            json={"langFilter": str(language)},
1677            auth=access_token,
1678        )
1679        assert isinstance(resp, dict)
1680        return resp
1681
1682    async def fetch_clan_fireteam(
1683        self, access_token: str, fireteam_id: int, group_id: int
1684    ) -> typedefs.JSONObject:
1685        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1686        resp = await self._request(
1687            RequestMethod.GET,
1688            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1689            auth=access_token,
1690        )
1691        assert isinstance(resp, dict)
1692        return resp
1693
1694    async def fetch_my_clan_fireteams(
1695        self,
1696        access_token: str,
1697        group_id: int,
1698        *,
1699        include_closed: bool = True,
1700        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1701        language: typing.Union[fireteams.FireteamLanguage, str],
1702        filtered: bool = True,
1703        page: int = 0,
1704    ) -> typedefs.JSONObject:
1705        payload = {"groupFilter": filtered, "langFilter": str(language)}
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET,
1709            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1710            json=payload,
1711            auth=access_token,
1712        )
1713        assert isinstance(resp, dict)
1714        return resp
1715
1716    async def fetch_private_clan_fireteams(
1717        self, access_token: str, group_id: int, /
1718    ) -> int:
1719        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1720        resp = await self._request(
1721            RequestMethod.GET,
1722            f"Fireteam/Clan/{group_id}/ActiveCount",
1723            auth=access_token,
1724        )
1725        assert isinstance(resp, int)
1726        return resp
1727
1728    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1729        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1730        resp = await self._request(
1731            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1732        )
1733        assert isinstance(resp, dict)
1734        return resp
1735
1736    async def search_entities(
1737        self, name: str, entity_type: str, *, page: int = 0
1738    ) -> typedefs.JSONObject:
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1743            json={"page": page},
1744        )
1745        assert isinstance(resp, dict)
1746        return resp
1747
1748    async def fetch_unique_weapon_history(
1749        self,
1750        membership_id: int,
1751        character_id: int,
1752        membership_type: typedefs.IntAnd[enums.MembershipType],
1753    ) -> typedefs.JSONObject:
1754        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1755        resp = await self._request(
1756            RequestMethod.GET,
1757            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1758        )
1759        assert isinstance(resp, dict)
1760        return resp
1761
1762    async def fetch_item(
1763        self,
1764        member_id: int,
1765        item_id: int,
1766        membership_type: typedefs.IntAnd[enums.MembershipType],
1767        components: list[enums.ComponentType],
1768    ) -> typedefs.JSONObject:
1769        collector = _collect_components(components)
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(
1772            RequestMethod.GET,
1773            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1774        )
1775        assert isinstance(resp, dict)
1776        return resp
1777
1778    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1779        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1780        resp = await self._request(
1781            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1782        )
1783        assert isinstance(resp, dict)
1784        return resp
1785
1786    async def fetch_available_locales(self) -> typedefs.JSONObject:
1787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1788        resp = await self._request(
1789            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1790        )
1791        assert isinstance(resp, dict)
1792        return resp
1793
1794    async def fetch_common_settings(self) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796        resp = await self._request(RequestMethod.GET, "Settings")
1797        assert isinstance(resp, dict)
1798        return resp
1799
1800    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1802        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1803        assert isinstance(resp, dict)
1804        return resp
1805
1806    async def fetch_global_alerts(
1807        self, *, include_streaming: bool = False
1808    ) -> typedefs.JSONArray:
1809        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1810        resp = await self._request(
1811            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1812        )
1813        assert isinstance(resp, list)
1814        return resp
1815
1816    async def awainitialize_request(
1817        self,
1818        access_token: str,
1819        type: typing.Literal[0, 1],
1820        membership_type: typedefs.IntAnd[enums.MembershipType],
1821        /,
1822        *,
1823        affected_item_id: typing.Optional[int] = None,
1824        character_id: typing.Optional[int] = None,
1825    ) -> typedefs.JSONObject:
1826        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1827
1828        body = {"type": type, "membershipType": int(membership_type)}
1829
1830        if affected_item_id is not None:
1831            body["affectedItemId"] = affected_item_id
1832
1833        if character_id is not None:
1834            body["characterId"] = character_id
1835
1836        resp = await self._request(
1837            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1838        )
1839        assert isinstance(resp, dict)
1840        return resp
1841
1842    async def awaget_action_token(
1843        self, access_token: str, correlation_id: str, /
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        resp = await self._request(
1847            RequestMethod.POST,
1848            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1849            auth=access_token,
1850        )
1851        assert isinstance(resp, dict)
1852        return resp
1853
1854    async def awa_provide_authorization_result(
1855        self,
1856        access_token: str,
1857        selection: int,
1858        correlation_id: str,
1859        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1860    ) -> int:
1861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1862
1863        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1864
1865        resp = await self._request(
1866            RequestMethod.POST,
1867            "Destiny2/Awa/AwaProvideAuthorizationResult",
1868            json=body,
1869            auth=access_token,
1870        )
1871        assert isinstance(resp, int)
1872        return resp
1873
1874    async def fetch_vendors(
1875        self,
1876        access_token: str,
1877        character_id: int,
1878        membership_id: int,
1879        membership_type: typedefs.IntAnd[enums.MembershipType],
1880        /,
1881        components: list[enums.ComponentType],
1882        filter: typing.Optional[int] = None,
1883    ) -> typedefs.JSONObject:
1884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1885        components_ = _collect_components(components)
1886        route = (
1887            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1888            f"/Character/{character_id}/Vendors/?components={components_}"
1889        )
1890
1891        if filter is not None:
1892            route = route + f"&filter={filter}"
1893
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            route,
1897            auth=access_token,
1898        )
1899        assert isinstance(resp, dict)
1900        return resp
1901
1902    async def fetch_vendor(
1903        self,
1904        access_token: str,
1905        character_id: int,
1906        membership_id: int,
1907        membership_type: typedefs.IntAnd[enums.MembershipType],
1908        vendor_hash: int,
1909        /,
1910        components: list[enums.ComponentType],
1911    ) -> typedefs.JSONObject:
1912        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1913        components_ = _collect_components(components)
1914        resp = await self._request(
1915            RequestMethod.GET,
1916            (
1917                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1918                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1919            ),
1920            auth=access_token,
1921        )
1922        assert isinstance(resp, dict)
1923        return resp
1924
1925    async def fetch_application_api_usage(
1926        self,
1927        access_token: str,
1928        application_id: int,
1929        /,
1930        *,
1931        start: typing.Optional[datetime.datetime] = None,
1932        end: typing.Optional[datetime.datetime] = None,
1933    ) -> typedefs.JSONObject:
1934
1935        end_date, start_date = time.parse_date_range(end, start)
1936        resp = await self._request(
1937            RequestMethod.GET,
1938            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1939            auth=access_token,
1940        )
1941        assert isinstance(resp, dict)
1942        return resp
1943
1944    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1945        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1946        assert isinstance(resp, list)
1947        return resp
1948
1949    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1950        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1951        assert isinstance(resp, dict)
1952        return resp
1953
1954    async def fetch_content_by_id(
1955        self, id: int, locale: str, /, *, head: bool = False
1956    ) -> typedefs.JSONObject:
1957        resp = await self._request(
1958            RequestMethod.GET,
1959            f"Content/GetContentById/{id}/{locale}/",
1960            json={"head": head},
1961        )
1962        assert isinstance(resp, dict)
1963        return resp
1964
1965    async def fetch_content_by_tag_and_type(
1966        self, locale: str, tag: str, type: str, *, head: bool = False
1967    ) -> typedefs.JSONObject:
1968        resp = await self._request(
1969            RequestMethod.GET,
1970            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1971            json={"head": head},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
1975
1976    async def search_content_with_text(
1977        self,
1978        locale: str,
1979        /,
1980        content_type: str,
1981        search_text: str,
1982        tag: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.Undefined,
1985        source: undefined.UndefinedOr[str] = undefined.Undefined,
1986    ) -> typedefs.JSONObject:
1987
1988        body: typedefs.JSONObject = {}
1989
1990        body["ctype"] = content_type
1991        body["searchtext"] = search_text
1992        body["tag"] = tag
1993
1994        if page is not undefined.Undefined:
1995            body["currentpage"] = page
1996        else:
1997            body["currentpage"] = 1
1998
1999        if source is not undefined.Undefined:
2000            body["source"] = source
2001        else:
2002            source = ""
2003        resp = await self._request(
2004            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2005        )
2006        assert isinstance(resp, dict)
2007        return resp
2008
2009    async def search_content_by_tag_and_type(
2010        self,
2011        locale: str,
2012        tag: str,
2013        type: str,
2014        *,
2015        page: undefined.UndefinedOr[int] = undefined.Undefined,
2016    ) -> typedefs.JSONObject:
2017        body: typedefs.JSONObject = {}
2018        body["currentpage"] = 1 if page is undefined.Undefined else page
2019        resp = await self._request(
2020            RequestMethod.GET,
2021            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
2026
2027    async def search_help_articles(
2028        self, text: str, size: str, /
2029    ) -> typedefs.JSONObject:
2030        resp = await self._request(
2031            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2032        )
2033        assert isinstance(resp, dict)
2034        return resp
2035
2036    async def fetch_topics_page(
2037        self,
2038        category_filter: int,
2039        group: int,
2040        date_filter: int,
2041        sort: typing.Union[str, bytes],
2042        *,
2043        page: undefined.UndefinedOr[int] = undefined.Undefined,
2044        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2045        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2046    ) -> typedefs.JSONObject:
2047
2048        body: typedefs.JSONObject = {}
2049        if locales is not undefined.Undefined:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        if tag_filter is not undefined.Undefined:
2055            body["tagstring"] = tag_filter
2056        else:
2057            body["tagstring"] = ""
2058
2059        page = 0 if page is not undefined.Undefined else page
2060
2061        resp = await self._request(
2062            RequestMethod.GET,
2063            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2064            json=body,
2065        )
2066        assert isinstance(resp, dict)
2067        return resp
2068
2069    async def fetch_core_topics_page(
2070        self,
2071        category_filter: int,
2072        date_filter: int,
2073        sort: typing.Union[str, bytes],
2074        *,
2075        page: undefined.UndefinedOr[int] = undefined.Undefined,
2076        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2077    ) -> typedefs.JSONObject:
2078        body: typedefs.JSONObject = {}
2079
2080        if locales is not undefined.Undefined:
2081            body["locales"] = ",".join(str(locales))
2082        else:
2083            body["locales"] = ",".join([])
2084
2085        resp = await self._request(
2086            RequestMethod.GET,
2087            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2088            f"/{sort!s}/{date_filter}/{category_filter}/",
2089            json=body,
2090        )
2091        assert isinstance(resp, dict)
2092        return resp
2093
2094    async def fetch_posts_threaded_page(
2095        self,
2096        parent_post: bool,
2097        page: int,
2098        page_size: int,
2099        parent_post_id: int,
2100        reply_size: int,
2101        root_thread_mode: bool,
2102        sort_mode: int,
2103        show_banned: typing.Optional[str] = None,
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2108            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2109            json={"showbanned": show_banned},
2110        )
2111        assert isinstance(resp, dict)
2112        return resp
2113
2114    async def fetch_posts_threaded_page_from_child(
2115        self,
2116        child_id: bool,
2117        page: int,
2118        page_size: int,
2119        reply_size: int,
2120        root_thread_mode: bool,
2121        sort_mode: int,
2122        show_banned: typing.Optional[str] = None,
2123    ) -> typedefs.JSONObject:
2124        resp = await self._request(
2125            RequestMethod.GET,
2126            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2127            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2128            json={"showbanned": show_banned},
2129        )
2130        assert isinstance(resp, dict)
2131        return resp
2132
2133    async def fetch_post_and_parent(
2134        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2135    ) -> typedefs.JSONObject:
2136        resp = await self._request(
2137            RequestMethod.GET,
2138            f"Forum/GetPostAndParent/{child_id}/",
2139            json={"showbanned": show_banned},
2140        )
2141        assert isinstance(resp, dict)
2142        return resp
2143
2144    async def fetch_posts_and_parent_awaiting(
2145        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2146    ) -> typedefs.JSONObject:
2147        resp = await self._request(
2148            RequestMethod.GET,
2149            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2150            json={"showbanned": show_banned},
2151        )
2152        assert isinstance(resp, dict)
2153        return resp
2154
2155    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2156        resp = await self._request(
2157            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2158        )
2159        assert isinstance(resp, int)
2160        return resp
2161
2162    async def fetch_forum_tag_suggestions(
2163        self, partial_tag: str, /
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            "Forum/GetForumTagSuggestions/",
2168            json={"partialtag": partial_tag},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
2172
2173    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2174        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2175        assert isinstance(resp, dict)
2176        return resp
2177
2178    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2179        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2180        assert isinstance(resp, list)
2181        return resp
2182
2183    async def fetch_recommended_groups(
2184        self,
2185        accecss_token: str,
2186        /,
2187        *,
2188        date_range: int = 0,
2189        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
2190    ) -> typedefs.JSONArray:
2191        resp = await self._request(
2192            RequestMethod.POST,
2193            f"GroupV2/Recommended/{int(group_type)}/{date_range}/",
2194            auth=accecss_token,
2195        )
2196        assert isinstance(resp, list)
2197        return resp
2198
2199    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2200        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2201        assert isinstance(resp, dict)
2202        return resp
2203
2204    async def fetch_user_clan_invite_setting(
2205        self,
2206        access_token: str,
2207        /,
2208        membership_type: typedefs.IntAnd[enums.MembershipType],
2209    ) -> bool:
2210        resp = await self._request(
2211            RequestMethod.GET,
2212            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2213            auth=access_token,
2214        )
2215        assert isinstance(resp, bool)
2216        return resp
2217
2218    async def fetch_banned_group_members(
2219        self, access_token: str, group_id: int, /, *, page: int = 1
2220    ) -> typedefs.JSONObject:
2221        resp = await self._request(
2222            RequestMethod.GET,
2223            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2224            auth=access_token,
2225        )
2226        assert isinstance(resp, dict)
2227        return resp
2228
2229    async def fetch_pending_group_memberships(
2230        self, access_token: str, group_id: int, /, *, current_page: int = 1
2231    ) -> typedefs.JSONObject:
2232        resp = await self._request(
2233            RequestMethod.GET,
2234            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2235            auth=access_token,
2236        )
2237        assert isinstance(resp, dict)
2238        return resp
2239
2240    async def fetch_invited_group_memberships(
2241        self, access_token: str, group_id: int, /, *, current_page: int = 1
2242    ) -> typedefs.JSONObject:
2243        resp = await self._request(
2244            RequestMethod.GET,
2245            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2246            auth=access_token,
2247        )
2248        assert isinstance(resp, dict)
2249        return resp
2250
2251    async def invite_member_to_group(
2252        self,
2253        access_token: str,
2254        /,
2255        group_id: int,
2256        membership_id: int,
2257        membership_type: typedefs.IntAnd[enums.MembershipType],
2258        *,
2259        message: undefined.UndefinedOr[str] = undefined.Undefined,
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.POST,
2263            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2264            auth=access_token,
2265            json={"message": str(message)},
2266        )
2267        assert isinstance(resp, dict)
2268        return resp
2269
2270    async def cancel_group_member_invite(
2271        self,
2272        access_token: str,
2273        /,
2274        group_id: int,
2275        membership_id: int,
2276        membership_type: typedefs.IntAnd[enums.MembershipType],
2277    ) -> typedefs.JSONObject:
2278        resp = await self._request(
2279            RequestMethod.POST,
2280            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2281            auth=access_token,
2282        )
2283        assert isinstance(resp, dict)
2284        return resp
2285
2286    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2287        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2288        assert isinstance(resp, dict)
2289        return resp
2290
2291    async def fetch_historical_stats(
2292        self,
2293        character_id: int,
2294        membership_id: int,
2295        membership_type: typedefs.IntAnd[enums.MembershipType],
2296        day_start: datetime.datetime,
2297        day_end: datetime.datetime,
2298        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2299        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2300        *,
2301        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2302    ) -> typedefs.JSONObject:
2303
2304        end, start = time.parse_date_range(day_end, day_start)
2305        resp = await self._request(
2306            RequestMethod.GET,
2307            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2308            json={
2309                "dayend": end,
2310                "daystart": start,
2311                "groups": [str(int(group)) for group in groups],
2312                "modes": [str(int(mode)) for mode in modes],
2313                "periodType": int(period_type),
2314            },
2315        )
2316        assert isinstance(resp, dict)
2317        return resp
2318
2319    async def fetch_historical_stats_for_account(
2320        self,
2321        membership_id: int,
2322        membership_type: typedefs.IntAnd[enums.MembershipType],
2323        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2324    ) -> typedefs.JSONObject:
2325        resp = await self._request(
2326            RequestMethod.GET,
2327            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2328            json={"groups": [str(int(group)) for group in groups]},
2329        )
2330        assert isinstance(resp, dict)
2331        return resp
2332
2333    async def fetch_aggregated_activity_stats(
2334        self,
2335        character_id: int,
2336        membership_id: int,
2337        membership_type: typedefs.IntAnd[enums.MembershipType],
2338        /,
2339    ) -> typedefs.JSONObject:
2340        resp = await self._request(
2341            RequestMethod.GET,
2342            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2343            f"Character/{character_id}/Stats/AggregateActivityStats/",
2344        )
2345        assert isinstance(resp, dict)
2346        return resp

A RESTful client implementation for Bungie's API.

This client is designed to only make HTTP requests and return JSON objects to provide RESTful functionality.

This client is also used within aiobungie.Client which deserialize those returned JSON objects using the factory into Pythonic data classes objects which provide Python functionality.

Example
import aiobungie

async def main():
    async with aiobungie.RESTClient("TOKEN") as rest_client:
        req = await rest_client.fetch_clan_members(4389205)
        clan_members = req['results']
        for member in clan_members:
            for k, v in member['destinyUserInfo'].items():
                print(k, v)
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTClient( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_ratelimit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
411    def __init__(
412        self,
413        token: str,
414        /,
415        client_secret: typing.Optional[str] = None,
416        client_id: typing.Optional[int] = None,
417        *,
418        max_retries: int = 4,
419        max_ratelimit_retries: int = 3,
420        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
421    ) -> None:
422        self._session: typing.Optional[_Session] = None
423        self._lock: typing.Optional[asyncio.Lock] = None
424        self._client_secret = client_secret
425        self._client_id = client_id
426        self._token: str = token
427        self._max_retries = max_retries
428        self._max_rate_limit_retries = max_ratelimit_retries
429        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
430
431        self._set_debug_level(enable_debugging)
client_id: Optional[int]

Return the client id of this REST client if provided, Otherwise None.

metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

A mutable mapping storage for the user's needs.

This mapping is useful for storing any kind of data that the user may need.

Example
import aiobungie

client = aiobungie.RESTClient(…)

async with client:
    # Fetch auth tokens and store them
    client.metadata["tokens"] = await client.fetch_access_token("code")

# Some other time.
async with client:
    # Retrieve the tokens
    tokens: aiobungie.OAuth2Response = client.metadata["tokens"]

    # Use them to fetch your user.
    user = await client.fetch_current_user_memberships(tokens.access_token)
is_alive: bool

Returns True if the REST client is alive and False otherwise.

@typing.final
async def close(self) -> None:
445    @typing.final
446    async def close(self) -> None:
447        if self._session is not None:
448            await self._session.close()
449            self._session = None

Close this REST client session if it was acquired.

@typing.final
def enable_debugging( self, level: Union[Literal['TRACE'], bool, int] = False, file: Union[pathlib.Path, str, NoneType] = None, /) -> None:
451    @typing.final
452    def enable_debugging(
453        self,
454        level: typing.Union[typing.Literal["TRACE"], bool, int] = False,
455        file: typing.Optional[typing.Union[pathlib.Path, str]] = None,
456        /,
457    ) -> None:
458        self._set_debug_level(level, file)

Enables debugging for the REST calls.

Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
Parameters
  • level (str | bool | int): The level of debugging to enable.
  • file (pathlib.Path | str | None): The file path to write the debug logs to. If provided.
@typing.final
async def static_request( self, method: Union[aiobungie.RequestMethod, str], path: str, *, auth: Optional[str] = None, json: Optional[dict[str, Any]] = None) -> Union[dict[str, Any], list[Any], bytes, int, bool, NoneType]:
460    @typing.final
461    async def static_request(
462        self,
463        method: typing.Union[RequestMethod, str],
464        path: str,
465        *,
466        auth: typing.Optional[str] = None,
467        json: typing.Optional[dict[str, typing.Any]] = None,
468    ) -> ResponseSig:
469        return await self._request(method, path, auth=auth, json=json)

Perform an HTTP request given a valid Bungie endpoint.

Parameters
  • method (aiobungie.RequestMethod | str): The request method, This may be GET, POST, PUT, etc.
  • path (str): The Bungie endpoint or path. A path must look something like this Destiny2/3/Profile/46111239123/...
  • auth (str | None): An optional bearer token for methods that requires OAuth2 Authorization header.
  • json (dict[str, typing.Any] | None): An optional JSON data to include in the request.
Returns
  • aiobungie.rest.ResponseSig: The response payload.
@typing.final
def build_oauth2_url(self, client_id: Optional[int] = None) -> Optional[str]:
471    @typing.final
472    def build_oauth2_url(
473        self, client_id: typing.Optional[int] = None
474    ) -> typing.Optional[str]:
475        client_id = client_id or self._client_id
476        if client_id is None:
477            return None
478
479        return url.OAUTH2_EP_BUILDER.format(
480            oauth_endpoint=url.OAUTH_EP,
481            client_id=client_id,
482            uuid=_uuid(),
483        )

Builds an OAuth2 URL using the provided user REST/Base client secret/id.

Parameters
  • client_id (int | None): An optional client id to provide, If left None it will roll back to the id passed to the RESTClient, If both is None this method will return None.
Returns
  • str | None: If the client id was provided as a parameter or provided in aiobungie.RESTClient, A complete URL will be returned. Otherwise None will be returned.
async def fetch_oauth2_tokens(self, code: str, /) -> aiobungie.builders.OAuth2Response:
715    async def fetch_oauth2_tokens(self, code: str, /) -> builders.OAuth2Response:
716
717        if not isinstance(self._client_id, int):
718            raise TypeError(
719                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
720            )
721
722        if not isinstance(self._client_secret, str):
723            raise TypeError(
724                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
725            )
726
727        headers = {
728            "client_secret": self._client_secret,
729        }
730
731        data = (
732            f"grant_type=authorization_code&code={code}"
733            f"&client_id={self._client_id}&client_secret={self._client_secret}"
734        )
735
736        response = await self._request(
737            RequestMethod.POST, "", headers=headers, data=data, oauth2=True
738        )
739        assert isinstance(response, dict)
740        return builders.OAuth2Response.build_response(response)

Makes a POST request and fetch the OAuth2 access_token and refresh token.

Parameters
  • code (str): The Authorization code received from the authorization endpoint found in the URL parameters.
Returns
Raises
async def refresh_access_token(self, refresh_token: str, /) -> aiobungie.builders.OAuth2Response:
742    async def refresh_access_token(
743        self, refresh_token: str, /
744    ) -> builders.OAuth2Response:
745        if not isinstance(self._client_id, int):
746            raise TypeError(
747                f"Expected (int) for client id but got {type(self._client_id).__qualname__}"  # type: ignore
748            )
749
750        if not isinstance(self._client_secret, str):
751            raise TypeError(
752                f"Expected (str) for client secret but got {type(self._client_secret).__qualname__}"  # type: ignore
753            )
754
755        data = {
756            "grant_type": "refresh_token",
757            "refresh_token": refresh_token,
758            "client_id": self._client_id,
759            "client_secret": self._client_secret,
760            "Content-Type": "application/x-www-form-urlencoded",
761        }
762
763        response = await self._request(RequestMethod.POST, "", data=data, oauth2=True)
764        assert isinstance(response, dict)
765        return builders.OAuth2Response.build_response(response)

Refresh OAuth2 access token given its refresh token.

Parameters
  • refresh_token (str): The refresh token.
Returns
async def fetch_bungie_user(self, id: int) -> dict[str, typing.Any]:
767    async def fetch_bungie_user(self, id: int) -> typedefs.JSONObject:
768        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
769        resp = await self._request(
770            RequestMethod.GET, f"User/GetBungieNetUserById/{id}/"
771        )
772        assert isinstance(resp, dict)
773        return resp

Fetch a Bungie user by their id.

Parameters
  • id (int): The user id.
Returns
Raises
async def fetch_user_themes(self) -> list[typing.Any]:
775    async def fetch_user_themes(self) -> typedefs.JSONArray:
776        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
777        resp = await self._request(RequestMethod.GET, "User/GetAvailableThemes/")
778        assert isinstance(resp, list)
779        return resp

Fetch all available user themes.

Returns
async def fetch_membership_from_id( self, id: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>, /) -> dict[str, typing.Any]:
781    async def fetch_membership_from_id(
782        self,
783        id: int,
784        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
785        /,
786    ) -> typedefs.JSONObject:
787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
788        resp = await self._request(
789            RequestMethod.GET, f"User/GetMembershipsById/{id}/{int(type)}"
790        )
791        assert isinstance(resp, dict)
792        return resp

Fetch Bungie user's memberships from their id.

Parameters
Returns
Raises
async def fetch_player( self, name: str, code: int, type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, /) -> list[typing.Any]:
794    async def fetch_player(
795        self,
796        name: str,
797        code: int,
798        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.ALL,
799        /,
800    ) -> typedefs.JSONArray:
801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
802        resp = await self._request(
803            RequestMethod.POST,
804            f"Destiny2/SearchDestinyPlayerByBungieName/{int(type)}",
805            json={"displayName": name, "displayNameCode": code},
806        )
807        assert isinstance(resp, list)
808        return resp

Fetch a Destiny 2 Player.

Parameters
Returns
Raises
async def search_users(self, name: str, /) -> dict[str, typing.Any]:
810    async def search_users(self, name: str, /) -> typedefs.JSONObject:
811        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
812        resp = await self._request(
813            RequestMethod.POST,
814            "User/Search/GlobalName/0",
815            json={"displayNamePrefix": name},
816        )
817        assert isinstance(resp, dict)
818        return resp

Search for users by their global name and return all users who share this name.

Parameters
  • name (str): The user name.
Returns
Raises
async def fetch_clan_from_id( self, id: int, /, access_token: Optional[str] = None) -> dict[str, typing.Any]:
820    async def fetch_clan_from_id(
821        self, id: int, /, access_token: typing.Optional[str] = None
822    ) -> typedefs.JSONObject:
823        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
824        resp = await self._request(
825            RequestMethod.GET, f"GroupV2/{id}", auth=access_token
826        )
827        assert isinstance(resp, dict)
828        return resp

Fetch a Bungie Clan by its id.

Parameters
  • id (int): The clan id.
Other Parameters
  • access_token (typing.Optional[str]): An optional access token to make the request with.

    If the token was bound to a member of the clan, This field aiobungie.crates.Clan.current_user_membership will be available and will return the membership of the user who made this request.

Returns
Raises
async def fetch_clan( self, name: str, /, access_token: Optional[str] = None, *, type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
830    async def fetch_clan(
831        self,
832        name: str,
833        /,
834        access_token: typing.Optional[str] = None,
835        *,
836        type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
837    ) -> typedefs.JSONObject:
838        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
839        resp = await self._request(
840            RequestMethod.GET, f"GroupV2/Name/{name}/{int(type)}", auth=access_token
841        )
842        assert isinstance(resp, dict)
843        return resp

Fetch a Clan by its name. This method will return the first clan found with given name name.

Parameters
  • name (str): The clan name.
Other Parameters
Returns
Raises
async def fetch_clan_admins(self, clan_id: int, /) -> dict[str, typing.Any]:
845    async def fetch_clan_admins(self, clan_id: int, /) -> typedefs.JSONObject:
846        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
847        resp = await self._request(
848            RequestMethod.GET, f"GroupV2/{clan_id}/AdminsAndFounder/"
849        )
850        assert isinstance(resp, dict)
851        return resp

Fetch the admins and founder members of the clan.

Parameters
  • clan_id (int): The clan id.
Returns
Raises
async def fetch_clan_conversations(self, clan_id: int, /) -> list[typing.Any]:
853    async def fetch_clan_conversations(self, clan_id: int, /) -> typedefs.JSONArray:
854        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
855        resp = await self._request(
856            RequestMethod.GET, f"GroupV2/{clan_id}/OptionalConversations/"
857        )
858        assert isinstance(resp, list)
859        return resp

Fetch a clan's conversations.

Parameters
  • clan_id (int): The clan's id.
Returns
async def fetch_application(self, appid: int, /) -> dict[str, typing.Any]:
861    async def fetch_application(self, appid: int, /) -> typedefs.JSONObject:
862        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
863        resp = await self._request(RequestMethod.GET, f"App/Application/{appid}")
864        assert isinstance(resp, dict)
865        return resp

Fetch a Bungie Application.

Parameters
  • appid (int): The application id.
Returns
async def fetch_character( self, member_id: int, membership_type: Union[int, aiobungie.MembershipType], character_id: int, components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
867    async def fetch_character(
868        self,
869        member_id: int,
870        membership_type: typedefs.IntAnd[enums.MembershipType],
871        character_id: int,
872        components: list[enums.ComponentType],
873        auth: typing.Optional[str] = None,
874    ) -> typedefs.JSONObject:
875        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
876        collector = _collect_components(components)
877        response = await self._request(
878            RequestMethod.GET,
879            f"Destiny2/{int(membership_type)}/Profile/{member_id}/"
880            f"Character/{character_id}/?components={collector}",
881            auth=auth,
882        )
883        assert isinstance(response, dict)
884        return response

Fetch a Destiny 2 player's characters.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_activities( self, member_id: int, character_id: int, mode: Union[int, aiobungie.GameMode], membership_type: Union[int, aiobungie.MembershipType] = <MembershipType.ALL: -1>, *, page: int = 0, limit: int = 1) -> dict[str, typing.Any]:
886    async def fetch_activities(
887        self,
888        member_id: int,
889        character_id: int,
890        mode: typedefs.IntAnd[enums.GameMode],
891        membership_type: typedefs.IntAnd[
892            enums.MembershipType
893        ] = enums.MembershipType.ALL,
894        *,
895        page: int = 0,
896        limit: int = 1,
897    ) -> typedefs.JSONObject:
898        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
899        resp = await self._request(
900            RequestMethod.GET,
901            f"Destiny2/{int(membership_type)}/Account/"
902            f"{member_id}/Character/{character_id}/Stats/Activities"
903            f"/?mode={int(mode)}&count={limit}&page={page}",
904        )
905        assert isinstance(resp, dict)
906        return resp

Fetch a Destiny 2 activity for the specified user id and character.

Parameters
  • member_id (int): The user id that starts with 4611.
  • character_id (int): The id of the character to retrieve.
  • mode (aiobungie.typedefs.IntAnd[aiobungie.GameMode]): This parameter filters the game mode, Nightfall, Strike, Iron Banner, etc.
Other Parameters
Returns
Raises
async def fetch_vendor_sales(self) -> dict[str, typing.Any]:
908    async def fetch_vendor_sales(self) -> typedefs.JSONObject:
909        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
910        resp = await self._request(
911            RequestMethod.GET,
912            f"Destiny2/Vendors/?components={int(enums.ComponentType.VENDOR_SALES)}",
913        )
914        assert isinstance(resp, dict)
915        return resp
async def fetch_profile( self, membership_id: int, type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType], auth: Optional[str] = None) -> dict[str, typing.Any]:
917    async def fetch_profile(
918        self,
919        membership_id: int,
920        type: typedefs.IntAnd[enums.MembershipType],
921        components: list[enums.ComponentType],
922        auth: typing.Optional[str] = None,
923    ) -> typedefs.JSONObject:
924        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
925        collector = _collect_components(components)
926        response = await self._request(
927            RequestMethod.GET,
928            f"Destiny2/{int(type)}/Profile/{membership_id}/?components={collector}",
929            auth=auth,
930        )
931        assert isinstance(response, dict)
932        return response

Fetch a bungie profile.

Parameters
Other Parameters
  • auth (typing.Optional[str]): A bearer access_token to make the request with. This is optional and limited to components that only requires an Authorization token.
Returns
Raises
async def fetch_entity(self, type: str, hash: int) -> dict[str, typing.Any]:
934    async def fetch_entity(self, type: str, hash: int) -> typedefs.JSONObject:
935        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
936        response = await self._request(
937            RequestMethod.GET, route=f"Destiny2/Manifest/{type}/{hash}"
938        )
939        assert isinstance(response, dict)
940        return response

Fetch a Destiny definition item given its type and hash.

Parameters
  • type (str): Entity's type definition.
  • hash (int): Entity's hash.
Returns
async def fetch_inventory_item(self, hash: int, /) -> dict[str, typing.Any]:
942    async def fetch_inventory_item(self, hash: int, /) -> typedefs.JSONObject:
943        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
944        resp = await self.fetch_entity("DestinyInventoryItemDefinition", hash)
945        assert isinstance(resp, dict)
946        return resp

Fetch a Destiny inventory item entity given a its hash.

Parameters
  • hash (int): Entity's hash.
Returns
async def fetch_objective_entity(self, hash: int, /) -> dict[str, typing.Any]:
948    async def fetch_objective_entity(self, hash: int, /) -> typedefs.JSONObject:
949        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
950        resp = await self.fetch_entity("DestinyObjectiveDefinition", hash)
951        assert isinstance(resp, dict)
952        return resp

Fetch a Destiny objective entity given a its hash.

Parameters
  • hash (int): objective's hash.
Returns
async def fetch_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
954    async def fetch_groups_for_member(
955        self,
956        member_id: int,
957        member_type: typedefs.IntAnd[enums.MembershipType],
958        /,
959        *,
960        filter: int = 0,
961        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
962    ) -> typedefs.JSONObject:
963        resp = await self._request(
964            RequestMethod.GET,
965            f"GroupV2/User/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
966        )
967        assert isinstance(resp, dict)
968        return resp

Fetch the information about the groups for a member.

Parameters
Other Parameters
Returns
async def fetch_potential_groups_for_member( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, filter: int = 0, group_type: Union[int, aiobungie.GroupType] = <GroupType.CLAN: 1>) -> dict[str, typing.Any]:
970    async def fetch_potential_groups_for_member(
971        self,
972        member_id: int,
973        member_type: typedefs.IntAnd[enums.MembershipType],
974        /,
975        *,
976        filter: int = 0,
977        group_type: typedefs.IntAnd[enums.GroupType] = enums.GroupType.CLAN,
978    ) -> typedefs.JSONObject:
979        resp = await self._request(
980            RequestMethod.GET,
981            f"GroupV2/User/Potential/{int(member_type)}/{member_id}/{filter}/{int(group_type)}/",
982        )
983        assert isinstance(resp, dict)
984        return resp

Get information about the groups that a given member has applied to or been invited to.

Parameters
Other Parameters
Returns
async def fetch_clan_members( self, clan_id: int, /, *, name: Optional[str] = None, type: Union[int, aiobungie.MembershipType] = <MembershipType.NONE: 0>) -> dict[str, typing.Any]:
 986    async def fetch_clan_members(
 987        self,
 988        clan_id: int,
 989        /,
 990        *,
 991        name: typing.Optional[str] = None,
 992        type: typedefs.IntAnd[enums.MembershipType] = enums.MembershipType.NONE,
 993    ) -> typedefs.JSONObject:
 994        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
 995        resp = await self._request(
 996            RequestMethod.GET,
 997            f"/GroupV2/{clan_id}/Members/?memberType={int(type)}&nameSearch={name if name else ''}&currentpage=1",
 998        )
 999        assert isinstance(resp, dict)
1000        return resp

Fetch all Bungie Clan members.

Parameters
  • clan_id (builsins.int): The clans id
Other Parameters
Returns
Raises
async def fetch_hardlinked_credentials( self, credential: int, type: Union[int, aiobungie.CredentialType] = <CredentialType.STEAMID: 12>, /) -> dict[str, typing.Any]:
1002    async def fetch_hardlinked_credentials(
1003        self,
1004        credential: int,
1005        type: typedefs.IntAnd[enums.CredentialType] = enums.CredentialType.STEAMID,
1006        /,
1007    ) -> typedefs.JSONObject:
1008        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1009        resp = await self._request(
1010            RequestMethod.GET,
1011            f"User/GetMembershipFromHardLinkedCredential/{int(type)}/{credential}/",
1012        )
1013        assert isinstance(resp, dict)
1014        return resp

Gets any hard linked membership given a credential.

Only works for credentials that are public just aiobungie.CredentialType.STEAMID right now. Cross Save aware.

Parameters
Returns
async def fetch_user_credentials(self, access_token: str, membership_id: int, /) -> list[typing.Any]:
1016    async def fetch_user_credentials(
1017        self, access_token: str, membership_id: int, /
1018    ) -> typedefs.JSONArray:
1019        resp = await self._request(
1020            RequestMethod.GET,
1021            f"User/GetCredentialTypesForTargetAccount/{membership_id}",
1022            auth=access_token,
1023        )
1024        assert isinstance(resp, list)
1025        return resp

Fetch an array of credential types attached to the requested account.

This method require OAuth2 Bearer access token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • membership_id (int): The id of the membership to return.
Returns
Raises
async def insert_socket_plug( self, action_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1027    async def insert_socket_plug(
1028        self,
1029        action_token: str,
1030        /,
1031        instance_id: int,
1032        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1033        character_id: int,
1034        membership_type: typedefs.IntAnd[enums.MembershipType],
1035    ) -> typedefs.JSONObject:
1036
1037        if isinstance(plug, builders.PlugSocketBuilder):
1038            plug = plug.collect()
1039
1040        body = {
1041            "actionToken": action_token,
1042            "itemInstanceId": instance_id,
1043            "plug": plug,
1044            "characterId": character_id,
1045            "membershipType": int(membership_type),
1046        }
1047        resp = await self._request(
1048            RequestMethod.POST, "Destiny2/Actions/Items/InsertSocketPlug", json=body
1049        )
1050        assert isinstance(resp, dict)
1051        return resp

Insert a plug into a socketed item.

OAuth2: AdvancedWriteActions scope is required

Parameters
  • action_token (str): Action token provided by the AwaGetActionToken API call.
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def insert_socket_plug_free( self, access_token: str, /, instance_id: int, plug: Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1053    async def insert_socket_plug_free(
1054        self,
1055        access_token: str,
1056        /,
1057        instance_id: int,
1058        plug: typing.Union[builders.PlugSocketBuilder, dict[str, int]],
1059        character_id: int,
1060        membership_type: typedefs.IntAnd[enums.MembershipType],
1061    ) -> typedefs.JSONObject:
1062
1063        if isinstance(plug, builders.PlugSocketBuilder):
1064            plug = plug.collect()
1065
1066        body = {
1067            "itemInstanceId": instance_id,
1068            "plug": plug,
1069            "characterId": character_id,
1070            "membershipType": int(membership_type),
1071        }
1072        resp = await self._request(
1073            RequestMethod.POST,
1074            "Destiny2/Actions/Items/InsertSocketPlugFree",
1075            json=body,
1076            auth=access_token,
1077        )
1078        assert isinstance(resp, dict)
1079        return resp

Insert a plug into a socketed item. This doesn't require an Action token.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • instance_id (int): The item instance id that's plug inserted.
  • plug (typing.Union[aiobungie.builders.PlugSocketBuilder, dict[str, int]]): Either a PlugSocketBuilder object or a raw dict contains key, value for the plug entries.
Example
plug = (
    aiobungie.PlugSocketBuilder()
    .set_socket_array(0)
    .set_socket_index(0)
    .set_plug_item(3023847)
    .collect()
)
await insert_socket_plug_free(..., plug=plug)

character_id : int The character's id. membership_type : aiobungie.typedefs.IntAnd[aiobungie.MembershipType] The membership type.

Returns
Raises
async def set_item_lock_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1081    async def set_item_lock_state(
1082        self,
1083        access_token: str,
1084        state: bool,
1085        /,
1086        item_id: int,
1087        character_id: int,
1088        membership_type: typedefs.IntAnd[enums.MembershipType],
1089    ) -> int:
1090        body = {
1091            "state": state,
1092            "itemId": item_id,
1093            "characterId": character_id,
1094            "membership_type": int(membership_type),
1095        }
1096        response = await self._request(
1097            RequestMethod.POST,
1098            "Destiny2/Actions/Items/SetLockState",
1099            json=body,
1100            auth=access_token,
1101        )
1102        assert isinstance(response, int)
1103        return response

Set the Lock State for an instanced item.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def set_quest_track_state( self, access_token: str, state: bool, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> int:
1105    async def set_quest_track_state(
1106        self,
1107        access_token: str,
1108        state: bool,
1109        /,
1110        item_id: int,
1111        character_id: int,
1112        membership_type: typedefs.IntAnd[enums.MembershipType],
1113    ) -> int:
1114        body = {
1115            "state": state,
1116            "itemId": item_id,
1117            "characterId": character_id,
1118            "membership_type": int(membership_type),
1119        }
1120        response = await self._request(
1121            RequestMethod.POST,
1122            "Destiny2/Actions/Items/SetTrackedState",
1123            json=body,
1124            auth=access_token,
1125        )
1126        assert isinstance(response, int)
1127        return response

Set the Tracking State for an instanced Quest or Bounty.

OAuth2: MoveEquipDestinyItems scope is required

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • state (bool): If True, The item will be locked, If False, The item will be unlocked.
  • item_id (int): The item id.
  • character_id (int): The character id.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type for the associated account.
Returns
  • int: An integer represents whether the request was successful or failed.
Raises
async def fetch_manifest_path(self) -> dict[str, typing.Any]:
1129    async def fetch_manifest_path(self) -> typedefs.JSONObject:
1130        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1131        path = await self._request(RequestMethod.GET, "Destiny2/Manifest")
1132        assert isinstance(path, dict)
1133        return path

Fetch the manifest JSON paths.

Returns
  • typedefs.JSONObject: The manifest JSON paths.
async def read_manifest_bytes(self, language: str = 'en', /) -> bytes:
1135    async def read_manifest_bytes(self, language: str = "en", /) -> bytes:
1136        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1137        _ensure_manifest_language(language)
1138
1139        content = await self.fetch_manifest_path()
1140        resp = await self._request(
1141            RequestMethod.GET,
1142            content["mobileWorldContentPaths"][language],
1143            unwrapping="read",
1144            base=True,
1145        )
1146        assert isinstance(resp, bytes)
1147        return resp

Read raw manifest SQLite database bytes response.

This method can be used to write the bytes to zipped file and then extract it to get the manifest content.

Parameters
  • language (str): The manifest database language bytes to get.
Returns
  • bytes: The bytes to read and write the manifest database.
async def download_manifest( self, language: str = 'en', name: str = 'manifest.sqlite3', *, force: bool = False) -> None:
1149    async def download_manifest(
1150        self,
1151        language: str = "en",
1152        name: str = "manifest.sqlite3",
1153        *,
1154        force: bool = False,
1155    ) -> None:
1156        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1157        if os.path.exists(name):
1158
1159            if force:
1160                _LOG.debug("Forcing manifest download.")
1161                os.remove(name)
1162
1163                return await self.download_manifest(language, name, force=force)
1164
1165            else:
1166                raise FileExistsError(
1167                    "Manifest file already exists, "
1168                    "If you want to force download, set the `force` parameter to `True`."
1169                )
1170
1171        _LOG.debug("Downloading manifest...")
1172        data_bytes = await self.read_manifest_bytes(language)
1173        await asyncio.get_running_loop().run_in_executor(
1174            None, _write_sqlite_bytes, data_bytes, name
1175        )

A helper method to download the manifest.

Note

This method downloads the sqlite database and not JSON. Use RESTInterface.download_json_manifest for the JSON version.

Parameters
  • language (str): The manifest language to download, Default is english.
  • name (str): The manifest database file name. Default is manifest.sqlite3
  • force (bool): Whether to force the download. Default is False. However if set to true the old file will get removed and a new one will being to download.
Returns
  • None
async def download_json_manifest(self, language: str = 'en') -> None:
1177    async def download_json_manifest(self, language: str = "en") -> None:
1178        _ensure_manifest_language(language)
1179
1180        _LOG.debug("Downloading manifest JSON...")
1181
1182        content = await self.fetch_manifest_path()
1183        json_bytes = await self._request(
1184            RequestMethod.GET,
1185            content["jsonWorldContentPaths"][language],
1186            unwrapping="read",
1187            base=True,
1188        )
1189
1190        await asyncio.get_running_loop().run_in_executor(
1191            None, _write_json_bytes, json_bytes
1192        )
1193        _LOG.debug("Finished downloading manifest JSON.")

Download the Bungie manifest json file.

Parameters
  • language (str): The language to download the manifest in.
async def fetch_manifest_version(self) -> str:
1195    async def fetch_manifest_version(self) -> str:
1196        return typing.cast(str, (await self.fetch_manifest_path())["version"])

Fetch the manifest version.

Returns
  • str: The manifest version.
@staticmethod
@helpers.deprecated(since='0.2.6a1', removed_in='0.2.6', use_instead='sqlite3.connect')
def connect_manifest( path: Optional[pathlib.Path] = None, connection: type[sqlite3.Connection] = ) -> sqlite3.Connection:
1198    @staticmethod
1199    @helpers.deprecated(
1200        since="0.2.6a1", removed_in="0.2.6", use_instead="sqlite3.connect"
1201    )
1202    def connect_manifest(
1203        path: typing.Optional[pathlib.Path] = None,
1204        connection: type[sqlite3.Connection] = sqlite3.Connection,
1205    ) -> sqlite3.Connection:
1206        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1207        path = path or pathlib.Path("./manifest.sqlite3")
1208        if not path.exists():
1209            raise FileNotFoundError(f"Manifest in path {path.name} doesn't exists.")
1210        return connection(path.name)

A helper method to connect to the manifest database.

Parameters
  • path (typing.Optional[pathlib.Path]): An optional path to pass, The assumed path to connect to is './manifest.sqlite3'
  • connection (type[sqlite3.Connection]): An optional connection to pass, if not passed a new connection will be created.
Returns
  • sqlite3.Connection: An SQLite database connection.
async def fetch_linked_profiles( self, member_id: int, member_type: Union[int, aiobungie.MembershipType], /, *, all: bool = False) -> dict[str, typing.Any]:
1212    async def fetch_linked_profiles(
1213        self,
1214        member_id: int,
1215        member_type: typedefs.IntAnd[enums.MembershipType],
1216        /,
1217        *,
1218        all: bool = False,
1219    ) -> typedefs.JSONObject:
1220        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1221        resp = await self._request(
1222            RequestMethod.GET,
1223            f"Destiny2/{int(member_type)}/Profile/{member_id}/LinkedProfiles/?getAllMemberships={all}",
1224        )
1225        assert isinstance(resp, dict)
1226        return resp

Returns a summary information about all profiles linked to the requested member.

The passed membership id/type maybe a Bungie.Net membership or a Destiny memberships.

It will only return linked accounts whose linkages you are allowed to view.

Parameters
Other Parameters
  • all (bool): If provided and set to True, All memberships regardless of whether thry're obscured by overrides will be returned,

    If provided and set to False, Only available memberships will be returned. The default for this is False.

Returns
async def fetch_clan_banners(self) -> dict[str, typing.Any]:
1228    async def fetch_clan_banners(self) -> typedefs.JSONObject:
1229        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1230        resp = await self._request(
1231            RequestMethod.GET, "Destiny2/Clan/ClanBannerDictionary/"
1232        )
1233        assert isinstance(resp, dict)
1234        return resp

Fetch the values of the clan banners.

Returns
async def fetch_public_milestones(self) -> dict[str, typing.Any]:
1236    async def fetch_public_milestones(self) -> typedefs.JSONObject:
1237        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1238        resp = await self._request(RequestMethod.GET, "Destiny2/Milestones/")
1239        assert isinstance(resp, dict)
1240        return resp

Fetch the available milestones.

Returns
async def fetch_public_milestone_content(self, milestone_hash: int, /) -> dict[str, typing.Any]:
1242    async def fetch_public_milestone_content(
1243        self, milestone_hash: int, /
1244    ) -> typedefs.JSONObject:
1245        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1246        resp = await self._request(
1247            RequestMethod.GET, f"Destiny2/Milestones/{milestone_hash}/Content/"
1248        )
1249        assert isinstance(resp, dict)
1250        return resp

Fetch the milestone content given its hash.

Parameters
  • milestone_hash (int): The milestone hash.
Returns
async def fetch_current_user_memberships(self, access_token: str, /) -> dict[str, typing.Any]:
1252    async def fetch_current_user_memberships(
1253        self, access_token: str, /
1254    ) -> typedefs.JSONObject:
1255        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1256        resp = await self._request(
1257            RequestMethod.GET,
1258            "User/GetMembershipsForCurrentUser/",
1259            auth=access_token,
1260        )
1261        assert isinstance(resp, dict)
1262        return resp

Fetch a bungie user's accounts with the signed in user. This GET method requires a Bearer access token for the authorization.

This requires OAuth2 scope enabled and the valid Bearer access_token.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def equip_item( self, access_token: str, /, item_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1264    async def equip_item(
1265        self,
1266        access_token: str,
1267        /,
1268        item_id: int,
1269        character_id: int,
1270        membership_type: typedefs.IntAnd[enums.MembershipType],
1271    ) -> None:
1272        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1273        payload = {
1274            "itemId": item_id,
1275            "characterId": character_id,
1276            "membershipType": int(membership_type),
1277        }
1278
1279        await self._request(
1280            RequestMethod.POST,
1281            "Destiny2/Actions/Items/EquipItem/",
1282            json=payload,
1283            auth=access_token,
1284        )

Equip an item to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item id.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def equip_items( self, access_token: str, /, item_ids: list[int], character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1286    async def equip_items(
1287        self,
1288        access_token: str,
1289        /,
1290        item_ids: list[int],
1291        character_id: int,
1292        membership_type: typedefs.IntAnd[enums.MembershipType],
1293    ) -> None:
1294        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1295        payload = {
1296            "itemIds": item_ids,
1297            "characterId": character_id,
1298            "membershipType": int(membership_type),
1299        }
1300        await self._request(
1301            RequestMethod.POST,
1302            "Destiny2/Actions/Items/EquipItems/",
1303            json=payload,
1304            auth=access_token,
1305        )

Equip multiple items to a character.

This requires the OAuth2: MoveEquipDestinyItems scope. Also You must have a valid Destiny account, and either be in a social space, in orbit or offline.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_ids (list[int]): A list of item ids.
  • character_id (int): The character's id to equip the item to.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The membership type assocaiated with this player.
async def ban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, length: int = 0, comment: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1307    async def ban_clan_member(
1308        self,
1309        access_token: str,
1310        /,
1311        group_id: int,
1312        membership_id: int,
1313        membership_type: typedefs.IntAnd[enums.MembershipType],
1314        *,
1315        length: int = 0,
1316        comment: undefined.UndefinedOr[str] = undefined.Undefined,
1317    ) -> None:
1318        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1319        payload = {"comment": str(comment), "length": length}
1320        await self._request(
1321            RequestMethod.POST,
1322            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Ban/",
1323            json=payload,
1324            auth=access_token,
1325        )

Bans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to ban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Other Parameters
  • length (int): An optional ban length.
  • comment (aiobungie.UndefinedOr[str]): An optional comment to this ban. Default is UNDEFINED
async def unban_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> None:
1327    async def unban_clan_member(
1328        self,
1329        access_token: str,
1330        /,
1331        group_id: int,
1332        membership_id: int,
1333        membership_type: typedefs.IntAnd[enums.MembershipType],
1334    ) -> None:
1335        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1336        await self._request(
1337            RequestMethod.POST,
1338            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Unban/",
1339            auth=access_token,
1340        )

Unbans a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to unban.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
async def kick_clan_member( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1342    async def kick_clan_member(
1343        self,
1344        access_token: str,
1345        /,
1346        group_id: int,
1347        membership_id: int,
1348        membership_type: typedefs.IntAnd[enums.MembershipType],
1349    ) -> typedefs.JSONObject:
1350        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1351        resp = await self._request(
1352            RequestMethod.POST,
1353            f"GroupV2/{group_id}/Members/{int(membership_type)}/{membership_id}/Kick/",
1354            auth=access_token,
1355        )
1356        assert isinstance(resp, dict)
1357        return resp

Kick a member from the clan.

This request requires OAuth2: oauth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
  • membership_id (int): The member id to kick.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The member's membership type.
Returns
async def edit_clan( self, access_token: str, /, group_id: int, *, name: Optional[str] = None, about: Optional[str] = None, motto: Optional[str] = None, theme: Optional[str] = None, tags: Optional[collections.abc.Sequence[str]] = None, is_public: Optional[bool] = None, locale: Optional[str] = None, avatar_image_index: Optional[int] = None, membership_option: Union[NoneType, int, aiobungie.MembershipOption] = None, allow_chat: Optional[bool] = None, chat_security: Optional[Literal[0, 1]] = None, call_sign: Optional[str] = None, homepage: Optional[Literal[0, 1, 2]] = None, enable_invite_messaging_for_admins: Optional[bool] = None, default_publicity: Optional[Literal[0, 1, 2]] = None, is_public_topic_admin: Optional[bool] = None) -> None:
1359    async def edit_clan(
1360        self,
1361        access_token: str,
1362        /,
1363        group_id: int,
1364        *,
1365        name: typedefs.NoneOr[str] = None,
1366        about: typedefs.NoneOr[str] = None,
1367        motto: typedefs.NoneOr[str] = None,
1368        theme: typedefs.NoneOr[str] = None,
1369        tags: typedefs.NoneOr[collections.Sequence[str]] = None,
1370        is_public: typedefs.NoneOr[bool] = None,
1371        locale: typedefs.NoneOr[str] = None,
1372        avatar_image_index: typedefs.NoneOr[int] = None,
1373        membership_option: typedefs.NoneOr[
1374            typedefs.IntAnd[enums.MembershipOption]
1375        ] = None,
1376        allow_chat: typedefs.NoneOr[bool] = None,
1377        chat_security: typedefs.NoneOr[typing.Literal[0, 1]] = None,
1378        call_sign: typedefs.NoneOr[str] = None,
1379        homepage: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1380        enable_invite_messaging_for_admins: typedefs.NoneOr[bool] = None,
1381        default_publicity: typedefs.NoneOr[typing.Literal[0, 1, 2]] = None,
1382        is_public_topic_admin: typedefs.NoneOr[bool] = None,
1383    ) -> None:
1384        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1385        payload = {
1386            "name": name,
1387            "about": about,
1388            "motto": motto,
1389            "theme": theme,
1390            "tags": tags,
1391            "isPublic": is_public,
1392            "avatarImageIndex": avatar_image_index,
1393            "isPublicTopicAdminOnly": is_public_topic_admin,
1394            "allowChat": allow_chat,
1395            "chatSecurity": chat_security,
1396            "callsign": call_sign,
1397            "homepage": homepage,
1398            "enableInvitationMessagingForAdmins": enable_invite_messaging_for_admins,
1399            "defaultPublicity": default_publicity,
1400            "locale": locale,
1401        }
1402        if membership_option is not None:
1403            payload["membershipOption"] = int(membership_option)
1404
1405        await self._request(
1406            RequestMethod.POST,
1407            f"GroupV2/{group_id}/Edit",
1408            json=payload,
1409            auth=access_token,
1410        )

Edit a clan.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id to edit.
Other Parameters
async def edit_clan_options( self, access_token: str, /, group_id: int, *, invite_permissions_override: Optional[bool] = None, update_culture_permissionOverride: Optional[bool] = None, host_guided_game_permission_override: Optional[Literal[0, 1, 2]] = None, update_banner_permission_override: Optional[bool] = None, join_level: Union[NoneType, int, aiobungie.ClanMemberType] = None) -> None:
1412    async def edit_clan_options(
1413        self,
1414        access_token: str,
1415        /,
1416        group_id: int,
1417        *,
1418        invite_permissions_override: typedefs.NoneOr[bool] = None,
1419        update_culture_permissionOverride: typedefs.NoneOr[bool] = None,
1420        host_guided_game_permission_override: typedefs.NoneOr[
1421            typing.Literal[0, 1, 2]
1422        ] = None,
1423        update_banner_permission_override: typedefs.NoneOr[bool] = None,
1424        join_level: typedefs.NoneOr[typedefs.IntAnd[enums.ClanMemberType]] = None,
1425    ) -> None:
1426
1427        payload = {
1428            "InvitePermissionOverride": invite_permissions_override,
1429            "UpdateCulturePermissionOverride": update_culture_permissionOverride,
1430            "HostGuidedGamePermissionOverride": host_guided_game_permission_override,
1431            "UpdateBannerPermissionOverride": update_banner_permission_override,
1432            "JoinLevel": int(join_level) if join_level else None,
1433        }
1434
1435        await self._request(
1436            RequestMethod.POST,
1437            f"GroupV2/{group_id}/EditFounderOptions",
1438            json=payload,
1439            auth=access_token,
1440        )

Edit the clan options.

Notes
  • This request requires OAuth2: oauth2: AdminGroups scope.
  • All arguments will default to None if not provided. This does not include access_token and group_id
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group id.
Other Parameters
  • invite_permissions_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to invite new members to group Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • update_culture_permissionOverride (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update group culture Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • host_guided_game_permission_override (aiobungie.typedefs.NoneOr[typing.Literal[0, 1, 2]]): Minimum Member Level allowed to host guided games Always Allowed: Founder, Acting Founder, Admin Allowed Overrides: 0 -> None, 1 -> Beginner 2 -> Member. Default is Member for clans, None for groups, although this means nothing for groups.
  • update_banner_permission_override (aiobungie.typedefs.NoneOr[bool]): Minimum Member Level allowed to update banner Always Allowed: Founder, Acting Founder True means admins have this power, false means they don't Default is False for clans, True for groups.
  • join_level (aiobungie.ClanMemberType): Level to join a member at when accepting an invite, application, or joining an open clan. Default is aiobungie.ClanMemberType.BEGINNER
async def fetch_friends(self, access_token: str, /) -> dict[str, typing.Any]:
1442    async def fetch_friends(self, access_token: str, /) -> typedefs.JSONObject:
1443        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1444        resp = await self._request(
1445            RequestMethod.GET,
1446            "Social/Friends/",
1447            auth=access_token,
1448        )
1449        assert isinstance(resp, dict)
1450        return resp

Fetch bungie friend list.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def fetch_friend_requests(self, access_token: str, /) -> dict[str, typing.Any]:
1452    async def fetch_friend_requests(self, access_token: str, /) -> typedefs.JSONObject:
1453        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1454        resp = await self._request(
1455            RequestMethod.GET,
1456            "Social/Friends/Requests",
1457            auth=access_token,
1458        )
1459        assert isinstance(resp, dict)
1460        return resp

Fetch pending bungie friend requests queue.

This requests OAuth2: ReadUserData scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
Returns
async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1462    async def accept_friend_request(self, access_token: str, /, member_id: int) -> None:
1463        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1464        await self._request(
1465            RequestMethod.POST,
1466            f"Social/Friends/Requests/Accept/{member_id}",
1467            auth=access_token,
1468        )

Accepts a friend relationship with the target user. The user must be on your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to accept.
async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1470    async def send_friend_request(self, access_token: str, /, member_id: int) -> None:
1471        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1472        await self._request(
1473            RequestMethod.POST,
1474            f"Social/Friends/Add/{member_id}",
1475            auth=access_token,
1476        )

Requests a friend relationship with the target user.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to send the request to.
async def decline_friend_request(self, access_token: str, /, member_id: int) -> None:
1478    async def decline_friend_request(
1479        self, access_token: str, /, member_id: int
1480    ) -> None:
1481        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1482        await self._request(
1483            RequestMethod.POST,
1484            f"Social/Friends/Requests/Decline/{member_id}",
1485            auth=access_token,
1486        )

Decline a friend request with the target user. The user must be in your incoming friend request list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to decline.
async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1488    async def remove_friend(self, access_token: str, /, member_id: int) -> None:
1489        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1490        await self._request(
1491            RequestMethod.POST,
1492            f"Social/Friends/Remove/{member_id}",
1493            auth=access_token,
1494        )

Removes a friend from your friend list. The user must be in your friend list.

This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove.
async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1496    async def remove_friend_request(self, access_token: str, /, member_id: int) -> None:
1497        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1498        await self._request(
1499            RequestMethod.POST,
1500            f"Social/Friends/Requests/Remove/{member_id}",
1501            auth=access_token,
1502        )

Removes a friend from your friend list requests. The user must be in your outgoing request list.

.. note : This request requires OAuth2: BnetWrite scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • member_id (int): The member's id to remove from the requested friend list.
async def approve_all_pending_group_users( self, access_token: str, /, group_id: int, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1504    async def approve_all_pending_group_users(
1505        self,
1506        access_token: str,
1507        /,
1508        group_id: int,
1509        message: undefined.UndefinedOr[str] = undefined.Undefined,
1510    ) -> None:
1511        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1512        await self._request(
1513            RequestMethod.POST,
1514            f"GroupV2/{group_id}/Members/ApproveAll",
1515            auth=access_token,
1516            json={"message": str(message)},
1517        )

Apporve all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def deny_all_pending_group_users( self, access_token: str, /, group_id: int, *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> None:
1519    async def deny_all_pending_group_users(
1520        self,
1521        access_token: str,
1522        /,
1523        group_id: int,
1524        *,
1525        message: undefined.UndefinedOr[str] = undefined.Undefined,
1526    ) -> None:
1527        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1528        await self._request(
1529            RequestMethod.POST,
1530            f"GroupV2/{group_id}/Members/DenyAll",
1531            auth=access_token,
1532            json={"message": str(message)},
1533        )

Deny all pending users for the given group id.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other Parameters
  • message (aiobungie.UndefinedOr[str]): An optional message to send with the request. Default is UNDEFINED.
async def add_optional_conversation( self, access_token: str, /, group_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0) -> None:
1535    async def add_optional_conversation(
1536        self,
1537        access_token: str,
1538        /,
1539        group_id: int,
1540        *,
1541        name: undefined.UndefinedOr[str] = undefined.Undefined,
1542        security: typing.Literal[0, 1] = 0,
1543    ) -> None:
1544        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1545        payload = {"chatName": str(name), "chatSecurity": security}
1546        await self._request(
1547            RequestMethod.POST,
1548            f"GroupV2/{group_id}/OptionalConversations/Add",
1549            json=payload,
1550            auth=access_token,
1551        )

Add a new chat channel to a group.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
Other parameters

name: aiobungie.UndefinedOr[str] The chat name. Default to UNDEFINED security: typing.Literal[0, 1] The security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`
async def edit_optional_conversation( self, access_token: str, /, group_id: int, conversation_id: int, *, name: Union[aiobungie.UndefinedType, str] = UNDEFINED, security: Literal[0, 1] = 0, enable_chat: bool = False) -> None:
1553    async def edit_optional_conversation(
1554        self,
1555        access_token: str,
1556        /,
1557        group_id: int,
1558        conversation_id: int,
1559        *,
1560        name: undefined.UndefinedOr[str] = undefined.Undefined,
1561        security: typing.Literal[0, 1] = 0,
1562        enable_chat: bool = False,
1563    ) -> None:
1564        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1565        payload = {
1566            "chatEnabled": enable_chat,
1567            "chatName": str(name),
1568            "chatSecurity": security,
1569        }
1570        await self._request(
1571            RequestMethod.POST,
1572            f"GroupV2/{group_id}/OptionalConversations/Edit/{conversation_id}",
1573            json=payload,
1574            auth=access_token,
1575        )

Edit the settings of this chat channel.

This request requires OAuth2: AdminGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The given group id.
  • conversation_id (int): The conversation/chat id.
Other parameters

name: aiobungie.UndefinedOr[str] The new chat name. Default to UNDEFINED security: typing.Literal[0, 1] The new security level of the chat.

If provided and set to 0, It will be to `Group` only.
If provided and set to 1, It will be `Admins` only.
Default is `0`

enable_chat : bool Whether to enable chatting or not. If set to True then chatting will be enabled. Otherwise it will be disabled.

async def transfer_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1577    async def transfer_item(
1578        self,
1579        access_token: str,
1580        /,
1581        item_id: int,
1582        item_hash: int,
1583        character_id: int,
1584        member_type: typedefs.IntAnd[enums.MembershipType],
1585        *,
1586        stack_size: int = 1,
1587        vault: bool = False,
1588    ) -> None:
1589        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1590        payload = {
1591            "characterId": character_id,
1592            "membershipType": int(member_type),
1593            "itemId": item_id,
1594            "itemReferenceHash": item_hash,
1595            "stackSize": stack_size,
1596            "transferToVault": vault,
1597        }
1598        await self._request(
1599            RequestMethod.POST,
1600            "Destiny2/Actions/Items/TransferItem",
1601            json=payload,
1602            auth=access_token,
1603        )

Transfer an item from / to your vault.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id you to transfer.
  • item_hash (int): The item hash.
  • character_id (int): The character id to transfer the item from/to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to trasnfer this item to your valut or not. Defaults to False.
async def pull_item( self, access_token: str, /, item_id: int, item_hash: int, character_id: int, member_type: Union[int, aiobungie.MembershipType], *, stack_size: int = 1, vault: bool = False) -> None:
1605    async def pull_item(
1606        self,
1607        access_token: str,
1608        /,
1609        item_id: int,
1610        item_hash: int,
1611        character_id: int,
1612        member_type: typedefs.IntAnd[enums.MembershipType],
1613        *,
1614        stack_size: int = 1,
1615        vault: bool = False,
1616    ) -> None:
1617        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>
1618        payload = {
1619            "characterId": character_id,
1620            "membershipType": int(member_type),
1621            "itemId": item_id,
1622            "itemReferenceHash": item_hash,
1623            "stackSize": stack_size,
1624            "transferToVault": vault,
1625        }
1626        await self._request(
1627            RequestMethod.POST,
1628            "Destiny2/Actions/Items/PullFromPostmaster",
1629            json=payload,
1630            auth=access_token,
1631        )

pull an item from the postmaster.

Notes
  • This method requires OAuth2: MoveEquipDestinyItems scope.
  • This method requires both item id and hash.
Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • item_id (int): The item instance id to pull.
  • item_hash (int): The item hash.
  • character_id (int): The character id to pull the item to.
  • member_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The user membership type.
Other Parameters
  • stack_size (int): The item stack size.
  • valut (bool): Whether to pill this item to your valut or not. Defaults to False.
async def fetch_fireteams( self, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform] = <FireteamPlatform.ANY: 0>, language: Union[aiobungie.FireteamLanguage, str] = <FireteamLanguage.ALL: >, date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, slots_filter: int = 0) -> dict[str, typing.Any]:
1633    async def fetch_fireteams(
1634        self,
1635        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1636        *,
1637        platform: typedefs.IntAnd[
1638            fireteams.FireteamPlatform
1639        ] = fireteams.FireteamPlatform.ANY,
1640        language: typing.Union[
1641            fireteams.FireteamLanguage, str
1642        ] = fireteams.FireteamLanguage.ALL,
1643        date_range: typedefs.IntAnd[
1644            fireteams.FireteamDate
1645        ] = fireteams.FireteamDate.ALL,
1646        page: int = 0,
1647        slots_filter: int = 0,
1648    ) -> typedefs.JSONObject:
1649        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1650        resp = await self._request(
1651            RequestMethod.GET,
1652            f"Fireteam/Search/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{page}/?langFilter={str(language)}",  # noqa: E501 Line too long
1653        )
1654        assert isinstance(resp, dict)
1655        return resp

Fetch public Bungie fireteams with open slots.

Parameters
Other Parameters
Returns
async def fetch_avaliable_clan_fireteams( self, access_token: str, group_id: int, activity_type: Union[int, aiobungie.FireteamActivity], *, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], date_range: Union[int, aiobungie.FireteamDate] = <FireteamDate.ALL: 0>, page: int = 0, public_only: bool = False, slots_filter: int = 0) -> dict[str, typing.Any]:
1657    async def fetch_avaliable_clan_fireteams(
1658        self,
1659        access_token: str,
1660        group_id: int,
1661        activity_type: typedefs.IntAnd[fireteams.FireteamActivity],
1662        *,
1663        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1664        language: typing.Union[fireteams.FireteamLanguage, str],
1665        date_range: typedefs.IntAnd[
1666            fireteams.FireteamDate
1667        ] = fireteams.FireteamDate.ALL,
1668        page: int = 0,
1669        public_only: bool = False,
1670        slots_filter: int = 0,
1671    ) -> typedefs.JSONObject:
1672        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1673        resp = await self._request(
1674            RequestMethod.GET,
1675            f"Fireteam/Clan/{group_id}/Available/{int(platform)}/{int(activity_type)}/{int(date_range)}/{slots_filter}/{public_only}/{page}",  # noqa: E501
1676            json={"langFilter": str(language)},
1677            auth=access_token,
1678        )
1679        assert isinstance(resp, dict)
1680        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id of the fireteam.
  • activity_type (aiobungie.typedefs.IntAnd[aiobungie.crates.FireteamActivity]): The fireteam activity type.
Other Parameters
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • date_range (aiobungie.typedefs.IntAnd[aiobungie.FireteamDate]): An integer to filter the date range of the returned fireteams. Defaults to aiobungie.FireteamDate.ALL.
  • page (int): The page number. By default its 0 which returns all available activities.
  • public_only (bool): If set to True, Then only public fireteams will be returned.
  • slots_filter (int): Filter the returned fireteams based on available slots. Default is 0
Returns
async def fetch_clan_fireteam( self, access_token: str, fireteam_id: int, group_id: int) -> dict[str, typing.Any]:
1682    async def fetch_clan_fireteam(
1683        self, access_token: str, fireteam_id: int, group_id: int
1684    ) -> typedefs.JSONObject:
1685        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1686        resp = await self._request(
1687            RequestMethod.GET,
1688            f"Fireteam/Clan/{group_id}/Summary/{fireteam_id}",
1689            auth=access_token,
1690        )
1691        assert isinstance(resp, dict)
1692        return resp

Fetch a specific clan fireteam.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch the fireteam from.
  • fireteam_id (int): The fireteam id to fetch.
Returns
async def fetch_my_clan_fireteams( self, access_token: str, group_id: int, *, include_closed: bool = True, platform: Union[int, aiobungie.FireteamPlatform], language: Union[aiobungie.FireteamLanguage, str], filtered: bool = True, page: int = 0) -> dict[str, typing.Any]:
1694    async def fetch_my_clan_fireteams(
1695        self,
1696        access_token: str,
1697        group_id: int,
1698        *,
1699        include_closed: bool = True,
1700        platform: typedefs.IntAnd[fireteams.FireteamPlatform],
1701        language: typing.Union[fireteams.FireteamLanguage, str],
1702        filtered: bool = True,
1703        page: int = 0,
1704    ) -> typedefs.JSONObject:
1705        payload = {"groupFilter": filtered, "langFilter": str(language)}
1706        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1707        resp = await self._request(
1708            RequestMethod.GET,
1709            f"Fireteam/Clan/{group_id}/My/{int(platform)}/{include_closed}/{page}",
1710            json=payload,
1711            auth=access_token,
1712        )
1713        assert isinstance(resp, dict)
1714        return resp

Fetch a clan's fireteams with open slots.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id to fetch.
Other Parameters
  • include_closed (bool): If provided and set to True, It will also return closed fireteams. If provided and set to False, It will only return public fireteams. Default is True.
  • platform (aiobungie.typedefs.IntAnd[aiobungie.FireteamPlatform]): If this is provided. Then the results will be filtered with the given platform. Defaults to aiobungie.crates.FireteamPlatform.ANY which returns all platforms.
  • language (typing.Union[aiobungie.FireteamLanguage, str]): A locale language to filter the used language in that fireteam. Defaults to aiobungie.crates.FireteamLanguage.ALL
  • filtered (bool): If set to True, it will filter by clan. Otherwise not. Default is True.
  • page (int): The page number. By default its 0 which returns all available activities.
Returns
async def fetch_private_clan_fireteams(self, access_token: str, group_id: int, /) -> int:
1716    async def fetch_private_clan_fireteams(
1717        self, access_token: str, group_id: int, /
1718    ) -> int:
1719        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1720        resp = await self._request(
1721            RequestMethod.GET,
1722            f"Fireteam/Clan/{group_id}/ActiveCount",
1723            auth=access_token,
1724        )
1725        assert isinstance(resp, int)
1726        return resp

Fetch the active count of the clan fireteams that are only private.

This method requires OAuth2: ReadGroups scope.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • group_id (int): The group/clan id.
Returns
  • int: The active fireteams count. Max value returned is 25.
async def fetch_post_activity(self, instance_id: int, /) -> dict[str, typing.Any]:
1728    async def fetch_post_activity(self, instance_id: int, /) -> typedefs.JSONObject:
1729        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1730        resp = await self._request(
1731            RequestMethod.GET, f"Destiny2/Stats/PostGameCarnageReport/{instance_id}"
1732        )
1733        assert isinstance(resp, dict)
1734        return resp

Fetch a post activity details.

Parameters
  • instance_id (int): The activity instance id.
Returns
async def search_entities( self, name: str, entity_type: str, *, page: int = 0) -> dict[str, typing.Any]:
1736    async def search_entities(
1737        self, name: str, entity_type: str, *, page: int = 0
1738    ) -> typedefs.JSONObject:
1739        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1740        resp = await self._request(
1741            RequestMethod.GET,
1742            f"Destiny2/Armory/Search/{entity_type}/{name}/",
1743            json={"page": page},
1744        )
1745        assert isinstance(resp, dict)
1746        return resp

Search for Destiny2 entities given a name and its type.

Parameters
  • name (str): The name of the entity, i.e., Thunderlord, One thousand voices.
  • entity_type (str): The type of the entity, AKA Definition, For an example DestinyInventoryItemDefinition
Other Parameters
  • page (int): An optional page to return. Default to 0.
Returns
async def fetch_unique_weapon_history( self, membership_id: int, character_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
1748    async def fetch_unique_weapon_history(
1749        self,
1750        membership_id: int,
1751        character_id: int,
1752        membership_type: typedefs.IntAnd[enums.MembershipType],
1753    ) -> typedefs.JSONObject:
1754        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1755        resp = await self._request(
1756            RequestMethod.GET,
1757            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/UniqueWeapons/",
1758        )
1759        assert isinstance(resp, dict)
1760        return resp

Fetch details about unique weapon usage for a character. Includes all exotics.

Parameters
Returns
async def fetch_item( self, member_id: int, item_id: int, membership_type: Union[int, aiobungie.MembershipType], components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1762    async def fetch_item(
1763        self,
1764        member_id: int,
1765        item_id: int,
1766        membership_type: typedefs.IntAnd[enums.MembershipType],
1767        components: list[enums.ComponentType],
1768    ) -> typedefs.JSONObject:
1769        collector = _collect_components(components)
1770        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1771        resp = await self._request(
1772            RequestMethod.GET,
1773            f"Destiny2/{int(membership_type)}/Profile/{member_id}/Item/{item_id}/?components={collector}",
1774        )
1775        assert isinstance(resp, dict)
1776        return resp

Fetch an instanced Destiny 2 item's details.

Parameters
Returns
async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> dict[str, typing.Any]:
1778    async def fetch_clan_weekly_rewards(self, clan_id: int, /) -> typedefs.JSONObject:
1779        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1780        resp = await self._request(
1781            RequestMethod.GET, f"Destiny2/Clan/{clan_id}/WeeklyRewardState/"
1782        )
1783        assert isinstance(resp, dict)
1784        return resp

Fetch the weekly reward state for a clan.

Parameters
  • clan_id (int): The clan id.
Returns
async def fetch_available_locales(self) -> dict[str, typing.Any]:
1786    async def fetch_available_locales(self) -> typedefs.JSONObject:
1787        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1788        resp = await self._request(
1789            RequestMethod.GET, "Destiny2/Manifest/DestinyLocaleDefinition/"
1790        )
1791        assert isinstance(resp, dict)
1792        return resp

Fetch available locales at Bungie.

Returns
async def fetch_common_settings(self) -> dict[str, typing.Any]:
1794    async def fetch_common_settings(self) -> typedefs.JSONObject:
1795        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1796        resp = await self._request(RequestMethod.GET, "Settings")
1797        assert isinstance(resp, dict)
1798        return resp

Fetch the common settings used by Bungie's envirotment.

Returns
async def fetch_user_systems_overrides(self) -> dict[str, typing.Any]:
1800    async def fetch_user_systems_overrides(self) -> typedefs.JSONObject:
1801        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1802        resp = await self._request(RequestMethod.GET, "UserSystemOverrides")
1803        assert isinstance(resp, dict)
1804        return resp

Fetch a user's specific system overrides.

Returns
async def fetch_global_alerts(self, *, include_streaming: bool = False) -> list[typing.Any]:
1806    async def fetch_global_alerts(
1807        self, *, include_streaming: bool = False
1808    ) -> typedefs.JSONArray:
1809        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1810        resp = await self._request(
1811            RequestMethod.GET, f"GlobalAlerts/?includestreaming={include_streaming}"
1812        )
1813        assert isinstance(resp, list)
1814        return resp

Fetch any active global alerts.

Parameters
  • include_streaming (bool): If True, the returned results will include streaming alerts. Default is False.
Returns
async def awainitialize_request( self, access_token: str, type: Literal[0, 1], membership_type: Union[int, aiobungie.MembershipType], /, *, affected_item_id: Optional[int] = None, character_id: Optional[int] = None) -> dict[str, typing.Any]:
1816    async def awainitialize_request(
1817        self,
1818        access_token: str,
1819        type: typing.Literal[0, 1],
1820        membership_type: typedefs.IntAnd[enums.MembershipType],
1821        /,
1822        *,
1823        affected_item_id: typing.Optional[int] = None,
1824        character_id: typing.Optional[int] = None,
1825    ) -> typedefs.JSONObject:
1826        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1827
1828        body = {"type": type, "membershipType": int(membership_type)}
1829
1830        if affected_item_id is not None:
1831            body["affectedItemId"] = affected_item_id
1832
1833        if character_id is not None:
1834            body["characterId"] = character_id
1835
1836        resp = await self._request(
1837            RequestMethod.POST, "Destiny2/Awa/Initialize", json=body, auth=access_token
1838        )
1839        assert isinstance(resp, dict)
1840        return resp

Initialize a request to perform an advanced write action.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • type (typing.Literal[0, 1]): Type of the advanced write action. Its either 0 or 1. If set to 0 that means it None. Otherwise if 1 that means its insert plugs.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type of the account to modify.
Other Parameters
  • affected_item_id (typing.Optional[int]): Item instance ID the action shall be applied to. This is optional for all but a new AwaType values.
  • character_id (typing.Optional[int]): The Destiny character ID to perform this action on.
Returns
async def awaget_action_token(self, access_token: str, correlation_id: str, /) -> dict[str, typing.Any]:
1842    async def awaget_action_token(
1843        self, access_token: str, correlation_id: str, /
1844    ) -> typedefs.JSONObject:
1845        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1846        resp = await self._request(
1847            RequestMethod.POST,
1848            f"Destiny2/Awa/GetActionToken/{correlation_id}",
1849            auth=access_token,
1850        )
1851        assert isinstance(resp, dict)
1852        return resp

Returns the action token if user approves the request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • correlation_id (str): The identifier for the advanced write action request.
Returns
async def awa_provide_authorization_result( self, access_token: str, selection: int, correlation_id: str, nonce: collections.abc.MutableSequence[typing.Union[str, bytes]]) -> int:
1854    async def awa_provide_authorization_result(
1855        self,
1856        access_token: str,
1857        selection: int,
1858        correlation_id: str,
1859        nonce: collections.MutableSequence[typing.Union[str, bytes]],
1860    ) -> int:
1861        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1862
1863        body = {"selection": selection, "correlationId": correlation_id, "nonce": nonce}
1864
1865        resp = await self._request(
1866            RequestMethod.POST,
1867            "Destiny2/Awa/AwaProvideAuthorizationResult",
1868            json=body,
1869            auth=access_token,
1870        )
1871        assert isinstance(resp, int)
1872        return resp

Provide the result of the user interaction. Called by the Bungie Destiny App to approve or reject a request.

OAuth2: AdvancedWriteActions application scope is required to perform this request.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • selection (int): Indication of the selection the user has made (Approving or rejecting the action)
  • correlation_id (str): Correlation ID of the request.
  • nonce (collections.MutableSequence[str, bytes]): Secret nonce received via the PUSH notification.
Returns
  • int: ...
async def fetch_vendors( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /, components: list[aiobungie.ComponentType], filter: Optional[int] = None) -> dict[str, typing.Any]:
1874    async def fetch_vendors(
1875        self,
1876        access_token: str,
1877        character_id: int,
1878        membership_id: int,
1879        membership_type: typedefs.IntAnd[enums.MembershipType],
1880        /,
1881        components: list[enums.ComponentType],
1882        filter: typing.Optional[int] = None,
1883    ) -> typedefs.JSONObject:
1884        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1885        components_ = _collect_components(components)
1886        route = (
1887            f"Destiny2/{int(membership_type)}/Profile/{membership_id}"
1888            f"/Character/{character_id}/Vendors/?components={components_}"
1889        )
1890
1891        if filter is not None:
1892            route = route + f"&filter={filter}"
1893
1894        resp = await self._request(
1895            RequestMethod.GET,
1896            route,
1897            auth=access_token,
1898        )
1899        assert isinstance(resp, dict)
1900        return resp

Get currently available vendors from the list of vendors that can possibly have rotating inventory.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Other Parameters
  • filter (int): Filters the type of items returned from the vendor. This can be left to None.
Returns
async def fetch_vendor( self, access_token: str, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], vendor_hash: int, /, components: list[aiobungie.ComponentType]) -> dict[str, typing.Any]:
1902    async def fetch_vendor(
1903        self,
1904        access_token: str,
1905        character_id: int,
1906        membership_id: int,
1907        membership_type: typedefs.IntAnd[enums.MembershipType],
1908        vendor_hash: int,
1909        /,
1910        components: list[enums.ComponentType],
1911    ) -> typedefs.JSONObject:
1912        # <<inherited docstring from aiobungie.interfaces.rest.RESTInterface>>.
1913        components_ = _collect_components(components)
1914        resp = await self._request(
1915            RequestMethod.GET,
1916            (
1917                f"Platform/Destiny2/{int(membership_type)}/Profile/{membership_id}"
1918                f"/Character/{character_id}/Vendors/{vendor_hash}/?components={components_}"
1919            ),
1920            auth=access_token,
1921        )
1922        assert isinstance(resp, dict)
1923        return resp

Fetch details for a specific vendor.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • character_id (int): The character ID to return the vendor info for.
  • membership_id (int): The Destiny membership id to return the vendor info for.
  • membership_type (aiobungie.typedefs.IntAnd[aiobungie.MembershipType]): The Destiny membership type to return the vendor info for.
  • vendor_hash (int): The vendor hash to return the details for.
  • components (list[aiobungie.ComponentType]): A list of vendor components to collect and return.
Returns
async def fetch_application_api_usage( self, access_token: str, application_id: int, /, *, start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None) -> dict[str, typing.Any]:
1925    async def fetch_application_api_usage(
1926        self,
1927        access_token: str,
1928        application_id: int,
1929        /,
1930        *,
1931        start: typing.Optional[datetime.datetime] = None,
1932        end: typing.Optional[datetime.datetime] = None,
1933    ) -> typedefs.JSONObject:
1934
1935        end_date, start_date = time.parse_date_range(end, start)
1936        resp = await self._request(
1937            RequestMethod.GET,
1938            f"App/ApiUsage/{application_id}/?end={end_date}&start={start_date}",
1939            auth=access_token,
1940        )
1941        assert isinstance(resp, dict)
1942        return resp

Fetch a Bungie application's API usage.

Parameters
  • access_token (str): The bearer access token associated with the bungie account.
  • application_id (int): The application id to get.
Other Parameters
  • start (typing.Optional[datetime.datetime]): A datetime object can be used to collect the start of the application usage. This is limited and can go back to 30 days maximum.

    If this is left to None. It will return the last 24 hours.

  • end (typing.Optional[datetime.datetime]): A datetime object can be used to collect the end of the application usage.

    If this is left to None. It will return now.

Example
import datetime

# Fetch data from 2021 Dec 10th to 2021 Dec 20th
await fetch_application_api_usage(
    start=datetime.datetime(2021, 12, 10), end=datetime.datetime(2021, 12, 20)
)
Returns
async def fetch_bungie_applications(self) -> list[typing.Any]:
1944    async def fetch_bungie_applications(self) -> typedefs.JSONArray:
1945        resp = await self._request(RequestMethod.GET, "App/FirstParty")
1946        assert isinstance(resp, list)
1947        return resp

Fetch details for applications created by Bungie.

Returns
async def fetch_content_type(self, type: str, /) -> dict[str, typing.Any]:
1949    async def fetch_content_type(self, type: str, /) -> typedefs.JSONObject:
1950        resp = await self._request(RequestMethod.GET, f"Content/GetContentType/{type}/")
1951        assert isinstance(resp, dict)
1952        return resp
async def fetch_content_by_id( self, id: int, locale: str, /, *, head: bool = False) -> dict[str, typing.Any]:
1954    async def fetch_content_by_id(
1955        self, id: int, locale: str, /, *, head: bool = False
1956    ) -> typedefs.JSONObject:
1957        resp = await self._request(
1958            RequestMethod.GET,
1959            f"Content/GetContentById/{id}/{locale}/",
1960            json={"head": head},
1961        )
1962        assert isinstance(resp, dict)
1963        return resp
async def fetch_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, head: bool = False) -> dict[str, typing.Any]:
1965    async def fetch_content_by_tag_and_type(
1966        self, locale: str, tag: str, type: str, *, head: bool = False
1967    ) -> typedefs.JSONObject:
1968        resp = await self._request(
1969            RequestMethod.GET,
1970            f"Content/GetContentByTagAndType/{tag}/{type}/{locale}/",
1971            json={"head": head},
1972        )
1973        assert isinstance(resp, dict)
1974        return resp
async def search_content_with_text( self, locale: str, /, content_type: str, search_text: str, tag: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, source: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
1976    async def search_content_with_text(
1977        self,
1978        locale: str,
1979        /,
1980        content_type: str,
1981        search_text: str,
1982        tag: str,
1983        *,
1984        page: undefined.UndefinedOr[int] = undefined.Undefined,
1985        source: undefined.UndefinedOr[str] = undefined.Undefined,
1986    ) -> typedefs.JSONObject:
1987
1988        body: typedefs.JSONObject = {}
1989
1990        body["ctype"] = content_type
1991        body["searchtext"] = search_text
1992        body["tag"] = tag
1993
1994        if page is not undefined.Undefined:
1995            body["currentpage"] = page
1996        else:
1997            body["currentpage"] = 1
1998
1999        if source is not undefined.Undefined:
2000            body["source"] = source
2001        else:
2002            source = ""
2003        resp = await self._request(
2004            RequestMethod.GET, f"Content/Search/{locale}/", json=body
2005        )
2006        assert isinstance(resp, dict)
2007        return resp
async def search_content_by_tag_and_type( self, locale: str, tag: str, type: str, *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED) -> dict[str, typing.Any]:
2009    async def search_content_by_tag_and_type(
2010        self,
2011        locale: str,
2012        tag: str,
2013        type: str,
2014        *,
2015        page: undefined.UndefinedOr[int] = undefined.Undefined,
2016    ) -> typedefs.JSONObject:
2017        body: typedefs.JSONObject = {}
2018        body["currentpage"] = 1 if page is undefined.Undefined else page
2019        resp = await self._request(
2020            RequestMethod.GET,
2021            f"Content/SearchContentByTagAndType/{tag}/{type}/{locale}/",
2022            json=body,
2023        )
2024        assert isinstance(resp, dict)
2025        return resp
async def search_help_articles(self, text: str, size: str, /) -> dict[str, typing.Any]:
2027    async def search_help_articles(
2028        self, text: str, size: str, /
2029    ) -> typedefs.JSONObject:
2030        resp = await self._request(
2031            RequestMethod.GET, f"Content/SearchHelpArticles/{text}/{size}/"
2032        )
2033        assert isinstance(resp, dict)
2034        return resp
async def fetch_topics_page( self, category_filter: int, group: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED, tag_filter: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2036    async def fetch_topics_page(
2037        self,
2038        category_filter: int,
2039        group: int,
2040        date_filter: int,
2041        sort: typing.Union[str, bytes],
2042        *,
2043        page: undefined.UndefinedOr[int] = undefined.Undefined,
2044        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2045        tag_filter: undefined.UndefinedOr[str] = undefined.Undefined,
2046    ) -> typedefs.JSONObject:
2047
2048        body: typedefs.JSONObject = {}
2049        if locales is not undefined.Undefined:
2050            body["locales"] = ",".join(str(locales))
2051        else:
2052            body["locales"] = ",".join([])
2053
2054        if tag_filter is not undefined.Undefined:
2055            body["tagstring"] = tag_filter
2056        else:
2057            body["tagstring"] = ""
2058
2059        page = 0 if page is not undefined.Undefined else page
2060
2061        resp = await self._request(
2062            RequestMethod.GET,
2063            f"Forum/GetTopicsPaged/{page}/{0}/{group}/{sort!s}/{date_filter}/{category_filter}/",
2064            json=body,
2065        )
2066        assert isinstance(resp, dict)
2067        return resp
async def fetch_core_topics_page( self, category_filter: int, date_filter: int, sort: Union[str, bytes], *, page: Union[aiobungie.UndefinedType, int] = UNDEFINED, locales: Union[aiobungie.UndefinedType, collections.abc.Iterable[str]] = UNDEFINED) -> dict[str, typing.Any]:
2069    async def fetch_core_topics_page(
2070        self,
2071        category_filter: int,
2072        date_filter: int,
2073        sort: typing.Union[str, bytes],
2074        *,
2075        page: undefined.UndefinedOr[int] = undefined.Undefined,
2076        locales: undefined.UndefinedOr[collections.Iterable[str]] = undefined.Undefined,
2077    ) -> typedefs.JSONObject:
2078        body: typedefs.JSONObject = {}
2079
2080        if locales is not undefined.Undefined:
2081            body["locales"] = ",".join(str(locales))
2082        else:
2083            body["locales"] = ",".join([])
2084
2085        resp = await self._request(
2086            RequestMethod.GET,
2087            f"Forum/GetCoreTopicsPaged/{0 if page is undefined.Undefined else page}"
2088            f"/{sort!s}/{date_filter}/{category_filter}/",
2089            json=body,
2090        )
2091        assert isinstance(resp, dict)
2092        return resp
async def fetch_posts_threaded_page( self, parent_post: bool, page: int, page_size: int, parent_post_id: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2094    async def fetch_posts_threaded_page(
2095        self,
2096        parent_post: bool,
2097        page: int,
2098        page_size: int,
2099        parent_post_id: int,
2100        reply_size: int,
2101        root_thread_mode: bool,
2102        sort_mode: int,
2103        show_banned: typing.Optional[str] = None,
2104    ) -> typedefs.JSONObject:
2105        resp = await self._request(
2106            RequestMethod.GET,
2107            f"Forum/GetPostsThreadedPaged/{parent_post}/{page}/"
2108            f"{page_size}/{reply_size}/{parent_post_id}/{root_thread_mode}/{sort_mode}/",
2109            json={"showbanned": show_banned},
2110        )
2111        assert isinstance(resp, dict)
2112        return resp
async def fetch_posts_threaded_page_from_child( self, child_id: bool, page: int, page_size: int, reply_size: int, root_thread_mode: bool, sort_mode: int, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2114    async def fetch_posts_threaded_page_from_child(
2115        self,
2116        child_id: bool,
2117        page: int,
2118        page_size: int,
2119        reply_size: int,
2120        root_thread_mode: bool,
2121        sort_mode: int,
2122        show_banned: typing.Optional[str] = None,
2123    ) -> typedefs.JSONObject:
2124        resp = await self._request(
2125            RequestMethod.GET,
2126            f"Forum/GetPostsThreadedPagedFromChild/{child_id}/"
2127            f"{page}/{page_size}/{reply_size}/{root_thread_mode}/{sort_mode}/",
2128            json={"showbanned": show_banned},
2129        )
2130        assert isinstance(resp, dict)
2131        return resp
async def fetch_post_and_parent( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2133    async def fetch_post_and_parent(
2134        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2135    ) -> typedefs.JSONObject:
2136        resp = await self._request(
2137            RequestMethod.GET,
2138            f"Forum/GetPostAndParent/{child_id}/",
2139            json={"showbanned": show_banned},
2140        )
2141        assert isinstance(resp, dict)
2142        return resp
async def fetch_posts_and_parent_awaiting( self, child_id: int, /, *, show_banned: Optional[str] = None) -> dict[str, typing.Any]:
2144    async def fetch_posts_and_parent_awaiting(
2145        self, child_id: int, /, *, show_banned: typing.Optional[str] = None
2146    ) -> typedefs.JSONObject:
2147        resp = await self._request(
2148            RequestMethod.GET,
2149            f"Forum/GetPostAndParentAwaitingApproval/{child_id}/",
2150            json={"showbanned": show_banned},
2151        )
2152        assert isinstance(resp, dict)
2153        return resp
async def fetch_topic_for_content(self, content_id: int, /) -> int:
2155    async def fetch_topic_for_content(self, content_id: int, /) -> int:
2156        resp = await self._request(
2157            RequestMethod.GET, f"Forum/GetTopicForContent/{content_id}/"
2158        )
2159        assert isinstance(resp, int)
2160        return resp
async def fetch_forum_tag_suggestions(self, partial_tag: str, /) -> dict[str, typing.Any]:
2162    async def fetch_forum_tag_suggestions(
2163        self, partial_tag: str, /
2164    ) -> typedefs.JSONObject:
2165        resp = await self._request(
2166            RequestMethod.GET,
2167            "Forum/GetForumTagSuggestions/",
2168            json={"partialtag": partial_tag},
2169        )
2170        assert isinstance(resp, dict)
2171        return resp
async def fetch_poll(self, topic_id: int, /) -> dict[str, typing.Any]:
2173    async def fetch_poll(self, topic_id: int, /) -> typedefs.JSONObject:
2174        resp = await self._request(RequestMethod.GET, f"Forum/Poll/{topic_id}/")
2175        assert isinstance(resp, dict)
2176        return resp
async def fetch_recuirement_thread_summaries(self) -> list[typing.Any]:
2178    async def fetch_recuirement_thread_summaries(self) -> typedefs.JSONArray:
2179        resp = await self._request(RequestMethod.POST, "Forum/Recruit/Summaries/")
2180        assert isinstance(resp, list)
2181        return resp
async def fetch_available_avatars(self) -> collections.abc.Mapping[str, int]:
2199    async def fetch_available_avatars(self) -> collections.Mapping[str, int]:
2200        resp = await self._request(RequestMethod.GET, "GroupV2/GetAvailableAvatars/")
2201        assert isinstance(resp, dict)
2202        return resp
async def fetch_user_clan_invite_setting( self, access_token: str, /, membership_type: Union[int, aiobungie.MembershipType]) -> bool:
2204    async def fetch_user_clan_invite_setting(
2205        self,
2206        access_token: str,
2207        /,
2208        membership_type: typedefs.IntAnd[enums.MembershipType],
2209    ) -> bool:
2210        resp = await self._request(
2211            RequestMethod.GET,
2212            f"GroupV2/GetUserClanInviteSetting/{int(membership_type)}/",
2213            auth=access_token,
2214        )
2215        assert isinstance(resp, bool)
2216        return resp
async def fetch_banned_group_members( self, access_token: str, group_id: int, /, *, page: int = 1) -> dict[str, typing.Any]:
2218    async def fetch_banned_group_members(
2219        self, access_token: str, group_id: int, /, *, page: int = 1
2220    ) -> typedefs.JSONObject:
2221        resp = await self._request(
2222            RequestMethod.GET,
2223            f"GroupV2/{group_id}/Banned/?currentpage={page}",
2224            auth=access_token,
2225        )
2226        assert isinstance(resp, dict)
2227        return resp
async def fetch_pending_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2229    async def fetch_pending_group_memberships(
2230        self, access_token: str, group_id: int, /, *, current_page: int = 1
2231    ) -> typedefs.JSONObject:
2232        resp = await self._request(
2233            RequestMethod.GET,
2234            f"GroupV2/{group_id}/Members/Pending/?currentpage={current_page}",
2235            auth=access_token,
2236        )
2237        assert isinstance(resp, dict)
2238        return resp
async def fetch_invited_group_memberships( self, access_token: str, group_id: int, /, *, current_page: int = 1) -> dict[str, typing.Any]:
2240    async def fetch_invited_group_memberships(
2241        self, access_token: str, group_id: int, /, *, current_page: int = 1
2242    ) -> typedefs.JSONObject:
2243        resp = await self._request(
2244            RequestMethod.GET,
2245            f"GroupV2/{group_id}/Members/InvitedIndividuals/?currentpage={current_page}",
2246            auth=access_token,
2247        )
2248        assert isinstance(resp, dict)
2249        return resp
async def invite_member_to_group( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], *, message: Union[aiobungie.UndefinedType, str] = UNDEFINED) -> dict[str, typing.Any]:
2251    async def invite_member_to_group(
2252        self,
2253        access_token: str,
2254        /,
2255        group_id: int,
2256        membership_id: int,
2257        membership_type: typedefs.IntAnd[enums.MembershipType],
2258        *,
2259        message: undefined.UndefinedOr[str] = undefined.Undefined,
2260    ) -> typedefs.JSONObject:
2261        resp = await self._request(
2262            RequestMethod.POST,
2263            f"GroupV2/{group_id}/Members/IndividualInvite/{int(membership_type)}/{membership_id}/",
2264            auth=access_token,
2265            json={"message": str(message)},
2266        )
2267        assert isinstance(resp, dict)
2268        return resp
async def cancel_group_member_invite( self, access_token: str, /, group_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType]) -> dict[str, typing.Any]:
2270    async def cancel_group_member_invite(
2271        self,
2272        access_token: str,
2273        /,
2274        group_id: int,
2275        membership_id: int,
2276        membership_type: typedefs.IntAnd[enums.MembershipType],
2277    ) -> typedefs.JSONObject:
2278        resp = await self._request(
2279            RequestMethod.POST,
2280            f"GroupV2/{group_id}/Members/IndividualInviteCancel/{int(membership_type)}/{membership_id}/",
2281            auth=access_token,
2282        )
2283        assert isinstance(resp, dict)
2284        return resp
async def fetch_historical_definition(self) -> dict[str, typing.Any]:
2286    async def fetch_historical_definition(self) -> typedefs.JSONObject:
2287        resp = await self._request(RequestMethod.GET, "Destiny2/Stats/Definition/")
2288        assert isinstance(resp, dict)
2289        return resp
async def fetch_historical_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], day_start: datetime.datetime, day_end: datetime.datetime, groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]], modes: collections.abc.Sequence[typing.Union[int, aiobungie.GameMode]], *, period_type: aiobungie.internal.enums.PeriodType = <PeriodType.ALL_TIME: 2>) -> dict[str, typing.Any]:
2291    async def fetch_historical_stats(
2292        self,
2293        character_id: int,
2294        membership_id: int,
2295        membership_type: typedefs.IntAnd[enums.MembershipType],
2296        day_start: datetime.datetime,
2297        day_end: datetime.datetime,
2298        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2299        modes: collections.Sequence[typedefs.IntAnd[enums.GameMode]],
2300        *,
2301        period_type: enums.PeriodType = enums.PeriodType.ALL_TIME,
2302    ) -> typedefs.JSONObject:
2303
2304        end, start = time.parse_date_range(day_end, day_start)
2305        resp = await self._request(
2306            RequestMethod.GET,
2307            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Character/{character_id}/Stats/",
2308            json={
2309                "dayend": end,
2310                "daystart": start,
2311                "groups": [str(int(group)) for group in groups],
2312                "modes": [str(int(mode)) for mode in modes],
2313                "periodType": int(period_type),
2314            },
2315        )
2316        assert isinstance(resp, dict)
2317        return resp

Fetch historical stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • day_start (datetime.datetime): The start of the day to return the stats for.
  • day_end (datetime.datetime): The end of the day to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
  • modes (list[aiobungie.GameMode | int]): A list of game modes to return.
  • period_type (aiobungie.enums.PeriodType): The period type to return the stats for. This will return ALL_TIME by default if not modified.
Returns
async def fetch_historical_stats_for_account( self, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], groups: list[typing.Union[int, aiobungie.internal.enums.StatsGroupType]]) -> dict[str, typing.Any]:
2319    async def fetch_historical_stats_for_account(
2320        self,
2321        membership_id: int,
2322        membership_type: typedefs.IntAnd[enums.MembershipType],
2323        groups: list[typedefs.IntAnd[enums.StatsGroupType]],
2324    ) -> typedefs.JSONObject:
2325        resp = await self._request(
2326            RequestMethod.GET,
2327            f"Destiny2/{int(membership_type)}/Account/{membership_id}/Stats/",
2328            json={"groups": [str(int(group)) for group in groups]},
2329        )
2330        assert isinstance(resp, dict)
2331        return resp

Fetch historical stats for an account's membership.

Parameters
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
  • groups (list[aiobungie.StatsGroupType]): A list of stats groups to return.
Returns
async def fetch_aggregated_activity_stats( self, character_id: int, membership_id: int, membership_type: Union[int, aiobungie.MembershipType], /) -> dict[str, typing.Any]:
2333    async def fetch_aggregated_activity_stats(
2334        self,
2335        character_id: int,
2336        membership_id: int,
2337        membership_type: typedefs.IntAnd[enums.MembershipType],
2338        /,
2339    ) -> typedefs.JSONObject:
2340        resp = await self._request(
2341            RequestMethod.GET,
2342            f"Destiny2/{int(membership_type)}/Account/{membership_id}/"
2343            f"Character/{character_id}/Stats/AggregateActivityStats/",
2344        )
2345        assert isinstance(resp, dict)
2346        return resp

Fetch aggregated activity stats for a specific membership character.

Parameters
  • character_id (int): The character ID to return the stats for.
  • membership_id (int): The Destiny membership id to return the stats for.
  • membership_type (aiobungie.MembershipType | int): The Destiny membership type to return the stats for.
Returns
class RESTPool:
234class RESTPool:
235    """Pool of `RESTClient` instances.
236
237    This allows to create multiple instances of `RESTClient`s that can be acquired
238    which share the same connector and metadata.
239
240    Example
241    -------
242    ```py
243    import aiobungie
244
245    client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')
246
247    # Using a context manager to acquire an instance
248    # of the pool and close the connection after finishing.
249
250    async with client_pool.acquire() as client:
251        await client.download_manifest()
252        return client.build_oauth2_url()
253
254    async with client_pool.acquire() as client:
255        new_tokens = await client.refresh_access_token("token")
256        # Tokens now can be used from any pool.
257        client.metadata['tokens'] = new_tokens
258    ```
259
260    Parameters
261    ----------
262    token : `str`
263        A valid application token from Bungie's developer portal.
264
265    Other Parameters
266    ----------------
267    max_retries : `int`
268        The max retries number to retry if the request hit a `5xx` status code.
269    max_ratelimit_retries : `int`
270        The max retries number to retry if the request hit a `429` status code. Defaults to `3`.
271    client_secret : `typing.Optional[str]`
272        An optional application client secret,
273        This is only needed if you're fetching OAuth2 tokens with this client.
274    client_id : `typing.Optional[int]`
275        An optional application client id,
276        This is only needed if you're fetching OAuth2 tokens with this client.
277    enable_debugging : `bool | str`
278        Whether to enable logging responses or not.
279
280    Logging Levels
281    --------------
282    * `False`: This will disable logging.
283    * `True`: This will set the level to `DEBUG` and enable logging minimal information.
284    Like the response status, route, taken time and so on.
285    * `"TRACE" | aiobungie.TRACE`: This will log the response headers along with the minimal information.
286    """
287
288    __slots__ = (
289        "_token",
290        "_max_retries",
291        "_client_secret",
292        "_client_id",
293        "_max_rate_limit_retries",
294        "_metadata",
295        "_enable_debug",
296    )
297
298    # Looks like mypy doesn't like this.
299    if typing.TYPE_CHECKING:
300        _enable_debug: typing.Union[typing.Literal["TRACE"], bool, int]
301
302    def __init__(
303        self,
304        token: str,
305        /,
306        client_secret: typing.Optional[str] = None,
307        client_id: typing.Optional[int] = None,
308        *,
309        max_retries: int = 4,
310        max_rate_limit_retries: int = 3,
311        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
312    ) -> None:
313        self._client_secret = client_secret
314        self._client_id = client_id
315        self._token: str = token
316        self._max_retries = max_retries
317        self._max_rate_limit_retries = max_rate_limit_retries
318        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
319        self._enable_debug = enable_debugging
320
321    @property
322    def client_id(self) -> typing.Optional[int]:
323        return self._client_id
324
325    @property
326    def metadata(self) -> collections.MutableMapping[typing.Any, typing.Any]:
327        """Pool's Metadata. This is different from client instance metadata."""
328        return self._metadata
329
330    @typing.final
331    def acquire(self) -> RESTClient:
332        """Acquires a new `RESTClient` instance from this REST pool.
333
334        Returns
335        -------
336        `RESTClient`
337            An instance of a REST client.
338        """
339        instance = RESTClient(
340            self._token,
341            client_secret=self._client_secret,
342            client_id=self._client_id,
343            max_retries=self._max_retries,
344            max_ratelimit_retries=self._max_rate_limit_retries,
345            enable_debugging=self._enable_debug,
346        )
347        return instance

Pool of RESTClient instances.

This allows to create multiple instances of RESTClients that can be acquired which share the same connector and metadata.

Example
import aiobungie

client_pool = aiobungie.RESTPool("token", client_id=1234, client_secret='secret')

# Using a context manager to acquire an instance
# of the pool and close the connection after finishing.

async with client_pool.acquire() as client:
    await client.download_manifest()
    return client.build_oauth2_url()

async with client_pool.acquire() as client:
    new_tokens = await client.refresh_access_token("token")
    # Tokens now can be used from any pool.
    client.metadata['tokens'] = new_tokens
Parameters
  • token (str): A valid application token from Bungie's developer portal.
Other Parameters
  • max_retries (int): The max retries number to retry if the request hit a 5xx status code.
  • max_ratelimit_retries (int): The max retries number to retry if the request hit a 429 status code. Defaults to 3.
  • client_secret (typing.Optional[str]): An optional application client secret, This is only needed if you're fetching OAuth2 tokens with this client.
  • client_id (typing.Optional[int]): An optional application client id, This is only needed if you're fetching OAuth2 tokens with this client.
  • enable_debugging (bool | str): Whether to enable logging responses or not.
Logging Levels
  • False: This will disable logging.
  • True: This will set the level to DEBUG and enable logging minimal information. Like the response status, route, taken time and so on.
  • "TRACE" | aiobungie.TRACE: This will log the response headers along with the minimal information.
RESTPool( token: str, /, client_secret: Optional[str] = None, client_id: Optional[int] = None, *, max_retries: int = 4, max_rate_limit_retries: int = 3, enable_debugging: Union[Literal['TRACE'], bool, int] = False)
302    def __init__(
303        self,
304        token: str,
305        /,
306        client_secret: typing.Optional[str] = None,
307        client_id: typing.Optional[int] = None,
308        *,
309        max_retries: int = 4,
310        max_rate_limit_retries: int = 3,
311        enable_debugging: typing.Union[typing.Literal["TRACE"], bool, int] = False,
312    ) -> None:
313        self._client_secret = client_secret
314        self._client_id = client_id
315        self._token: str = token
316        self._max_retries = max_retries
317        self._max_rate_limit_retries = max_rate_limit_retries
318        self._metadata: collections.MutableMapping[typing.Any, typing.Any] = {}
319        self._enable_debug = enable_debugging
client_id: Optional[int]
metadata: collections.abc.MutableMapping[typing.Any, typing.Any]

Pool's Metadata. This is different from client instance metadata.

@typing.final
def acquire(self) -> aiobungie.RESTClient:
330    @typing.final
331    def acquire(self) -> RESTClient:
332        """Acquires a new `RESTClient` instance from this REST pool.
333
334        Returns
335        -------
336        `RESTClient`
337            An instance of a REST client.
338        """
339        instance = RESTClient(
340            self._token,
341            client_secret=self._client_secret,
342            client_id=self._client_id,
343            max_retries=self._max_retries,
344            max_ratelimit_retries=self._max_rate_limit_retries,
345            enable_debugging=self._enable_debug,
346        )
347        return instance

Acquires a new RESTClient instance from this REST pool.

Returns
@typing.final
class Race(builtins.int, aiobungie.Enum):
496@typing.final
497class Race(int, Enum):
498    """An Enum for Destiny races."""
499
500    HUMAN = 0
501    AWOKEN = 1
502    EXO = 2
503    UNKNOWN = 3

An Enum for Destiny races.

HUMAN = <Race.HUMAN: 0>
AWOKEN = <Race.AWOKEN: 1>
EXO = <Race.EXO: 2>
UNKNOWN = <Race.UNKNOWN: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Raid(builtins.int, aiobungie.Enum):
148@typing.final
149class Raid(int, Enum):
150    """An Enum for all available raids in Destiny 2."""
151
152    DSC = 910380154
153    """Deep Stone Crypt"""
154
155    LW = 2122313384
156    """Last Wish"""
157
158    VOG = 3881495763
159    """Normal Valut of Glass"""
160
161    GOS = 3458480158
162    """Garden Of Salvation"""

An Enum for all available raids in Destiny 2.

DSC = <Raid.DSC: 910380154>

Deep Stone Crypt

LW = <Raid.LW: 2122313384>

Last Wish

VOG = <Raid.VOG: 3881495763>

Normal Valut of Glass

GOS = <Raid.GOS: 3458480158>

Garden Of Salvation

Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@attrs.define(auto_exc=True)
class RateLimitedError(aiobungie.HTTPError):
213@attrs.define(auto_exc=True)
214class RateLimitedError(HTTPError):
215    """Raised when being hit with ratelimits."""
216
217    http_status: http.HTTPStatus = attrs.field(
218        default=http.HTTPStatus.TOO_MANY_REQUESTS, init=False
219    )
220    """The request response http status."""
221
222    url: typedefs.StrOrURL
223    """The URL/endpoint caused this error."""
224
225    body: typing.Any
226    """The response body."""
227
228    retry_after: float = attrs.field(default=0.0)
229    """The amount of seconds you need to wait before retrying to requests."""
230
231    message: str = attrs.field(init=False)
232    """A Bungie human readable message describes the cause of the error."""
233
234    @message.default  # type: ignore
235    def _(self) -> str:
236        return f"You're ratelimited for {self.retry_after}, Endpoint: {self.url}. Slow down!"
237
238    def __str__(self) -> str:
239        return self.message

Raised when being hit with ratelimits.

RateLimitedError(url: Union[str, yarl.URL], body: Any, retry_after: float = 0.0)
2def __init__(self, url, body, retry_after=attr_dict['retry_after'].default):
3    self.http_status = attr_dict['http_status'].default
4    self.url = url
5    self.body = body
6    self.retry_after = retry_after
7    self.message = __attr_factory_message(self)
8    BaseException.__init__(self, self.url,self.body,self.retry_after)

Method generated by attrs for class RateLimitedError.

http_status: http.HTTPStatus

The request response http status.

url: Union[str, yarl.URL]

The URL/endpoint caused this error.

body: Any

The response body.

retry_after: float

The amount of seconds you need to wait before retrying to requests.

message: str

A Bungie human readable message describes the cause of the error.

Inherited Members
builtins.BaseException
with_traceback
args
@typing.final
class RecordState(aiobungie.Flag):
49@typing.final
50class RecordState(enums.Flag):
51    """An enum for records component states."""
52
53    NONE = 0
54    REDEEMED = 1
55    UNAVAILABLE = 2
56    OBJECTIVE_NOT_COMPLETED = 4
57    OBSCURED = 8
58    INVISIBLE = 16
59    ENTITLEMENT_UNOWNED = 32
60    CAN_EQUIP_TITLE = 64

An enum for records component states.

NONE = <RecordState.NONE: 0>
REDEEMED = <RecordState.REDEEMED: 1>
UNAVAILABLE = <RecordState.UNAVAILABLE: 2>
OBJECTIVE_NOT_COMPLETED = <RecordState.OBJECTIVE_NOT_COMPLETED: 4>
OBSCURED = <RecordState.OBSCURED: 8>
INVISIBLE = <RecordState.INVISIBLE: 16>
ENTITLEMENT_UNOWNED = <RecordState.ENTITLEMENT_UNOWNED: 32>
CAN_EQUIP_TITLE = <RecordState.CAN_EQUIP_TITLE: 64>
Inherited Members
Flag
name
value
@typing.final
class Relationship(builtins.int, aiobungie.Enum):
691@typing.final
692class Relationship(int, Enum):
693    """An enum for bungie friends relationship types."""
694
695    UNKNOWN = 0
696    FRIEND = 1
697    INCOMING_REQUEST = 2
698    OUTGOING_REQUEST = 3

An enum for bungie friends relationship types.

UNKNOWN = <Relationship.UNKNOWN: 0>
FRIEND = <Relationship.FRIEND: 1>
INCOMING_REQUEST = <Relationship.INCOMING_REQUEST: 2>
OUTGOING_REQUEST = <Relationship.OUTGOING_REQUEST: 3>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
class RequestMethod(builtins.str, aiobungie.Enum):
215class RequestMethod(str, enums.Enum):
216    """HTTP request methods enum."""
217
218    GET = "GET"
219    """GET methods."""
220    POST = "POST"
221    """POST methods."""
222    PUT = "PUT"
223    """PUT methods."""
224    PATCH = "PATCH"
225    """PATCH methods."""
226    DELETE = "DELETE"
227    """DELETE methods"""

HTTP request methods enum.

GET = <RequestMethod.GET: GET>

GET methods.

POST = <RequestMethod.POST: POST>

POST methods.

PUT = <RequestMethod.PUT: PUT>

PUT methods.

PATCH = <RequestMethod.PATCH: PATCH>

PATCH methods.

DELETE = <RequestMethod.DELETE: DELETE>

DELETE methods

Inherited Members
Enum
name
value
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
@attrs.define(auto_exc=True)
class ResponseError(aiobungie.HTTPException):
208@attrs.define(auto_exc=True)
209class ResponseError(HTTPException):
210    """Standard HTTP responses exception."""

Standard HTTP responses exception.

ResponseError( *, error_code: int, http_status: http.HTTPStatus, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, http_status, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.http_status = http_status
 5    self.throttle_seconds = throttle_seconds
 6    self.url = url
 7    self.body = body
 8    self.headers = headers
 9    self.message = message
10    self.error_status = error_status
11    self.message_data = message_data
12    BaseException.__init__(self, self.error_code,self.http_status,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class ResponseError.

Inherited Members
HTTPException
error_code
http_status
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
@typing.final
class Stat(builtins.int, aiobungie.Enum):
518@typing.final
519class Stat(int, Enum):
520    """An Enum for Destiny 2 character stats."""
521
522    NONE = 0
523    MOBILITY = 2996146975
524    RESILIENCE = 392767087
525    RECOVERY = 1943323491
526    DISCIPLINE = 1735777505
527    INTELLECT = 144602215
528    STRENGTH = 4244567218
529    LIGHT_POWER = 1935470627

An Enum for Destiny 2 character stats.

NONE = <Stat.NONE: 0>
MOBILITY = <Stat.MOBILITY: 2996146975>
RESILIENCE = <Stat.RESILIENCE: 392767087>
RECOVERY = <Stat.RECOVERY: 1943323491>
DISCIPLINE = <Stat.DISCIPLINE: 1735777505>
INTELLECT = <Stat.INTELLECT: 144602215>
STRENGTH = <Stat.STRENGTH: 4244567218>
LIGHT_POWER = <Stat.LIGHT_POWER: 1935470627>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TRACE = 5
@typing.final
class TierType(builtins.int, aiobungie.Enum):
633@typing.final
634class TierType(int, Enum):
635    """An enum for a Destiny 2 item tier type."""
636
637    UNKNOWN = 0
638    CURRENCY = 1
639    BASIC = 2
640    COMMON = 3
641    RARE = 4
642    SUPERIOR = 5
643    EXOTIC = 6

An enum for a Destiny 2 item tier type.

UNKNOWN = <TierType.UNKNOWN: 0>
CURRENCY = <TierType.CURRENCY: 1>
BASIC = <TierType.BASIC: 2>
COMMON = <TierType.COMMON: 3>
RARE = <TierType.RARE: 4>
SUPERIOR = <TierType.SUPERIOR: 5>
EXOTIC = <TierType.EXOTIC: 6>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class TransferStatus(aiobungie.Flag):
743@typing.final
744class TransferStatus(Flag):
745    """An enum for items transfer statuses."""
746
747    CAN_TRANSFER = 0
748    """The item can be transferred."""
749    IS_EQUIPPED = 1
750    """You can't transfer since the item is equipped."""
751    NOT_TRASNFERRABLE = 2
752    """This item can not be transferred."""
753    COULD_BE_TRANSFERRED = 4
754    """You can trasnfer the item. But the place you're trying to put it at has no space for it."""

An enum for items transfer statuses.

CAN_TRANSFER = <TransferStatus.CAN_TRANSFER: 0>

The item can be transferred.

IS_EQUIPPED = <TransferStatus.IS_EQUIPPED: 1>

You can't transfer since the item is equipped.

NOT_TRASNFERRABLE = <TransferStatus.NOT_TRASNFERRABLE: 2>

This item can not be transferred.

COULD_BE_TRANSFERRED = <TransferStatus.COULD_BE_TRANSFERRED: 4>

You can trasnfer the item. But the place you're trying to put it at has no space for it.

Inherited Members
Flag
name
value
@attrs.define(auto_exc=True)
class Unauthorized(aiobungie.HTTPException):
151@attrs.define(auto_exc=True)
152class Unauthorized(HTTPException):
153    """Unauthorized access."""
154
155    http_status: http.HTTPStatus = attrs.field(
156        default=http.HTTPStatus.UNAUTHORIZED, init=False
157    )

Unauthorized access.

Unauthorized( *, error_code: int, throttle_seconds: int, url: Union[str, yarl.URL, NoneType], body: Any, headers: multidict._multidict.CIMultiDictProxy[str], message: str, error_status: str, message_data: dict[str, str])
 2def __init__(self, *, error_code, throttle_seconds, url, body, headers, message, error_status, message_data):
 3    self.error_code = error_code
 4    self.throttle_seconds = throttle_seconds
 5    self.url = url
 6    self.body = body
 7    self.headers = headers
 8    self.message = message
 9    self.error_status = error_status
10    self.message_data = message_data
11    self.http_status = attr_dict['http_status'].default
12    BaseException.__init__(self, self.error_code,self.throttle_seconds,self.url,self.body,self.headers,self.message,self.error_status,self.message_data)

Method generated by attrs for class Unauthorized.

http_status: http.HTTPStatus

The request response http status.

Inherited Members
HTTPException
error_code
throttle_seconds
url
body
headers
message
error_status
message_data
builtins.BaseException
with_traceback
args
Undefined = UNDEFINED
UndefinedOr = typing.Union[aiobungie.UndefinedType, +_T]
class UndefinedType:
33class UndefinedType:
34    """An `UNDEFINED` type."""
35
36    __instance: typing.Optional[UndefinedType] = None
37
38    def __bool__(self) -> typing.Literal[False]:
39        return False
40
41    def __int__(self) -> typing.Literal[0]:
42        return 0
43
44    def __repr__(self) -> str:
45        return "UNDEFINED"
46
47    def __str__(self) -> str:
48        return "UNDEFINED"
49
50    def __new__(cls) -> UndefinedType:
51        if cls.__instance is None:
52            o = super().__new__(cls)
53            cls.__instance = o
54        return cls.__instance

An UNDEFINED type.

UndefinedType()
@typing.final
class ValueUIStyle(builtins.int, aiobungie.Enum):
75@typing.final
76class ValueUIStyle(int, enums.Enum):
77    AUTOMATIC = 0
78    FRACTION = 1
79    CHECK_BOX = 2
80    PERCENTAGE = 3
81    DATETIME = 4
82    FRACTION_FLOAT = 5
83    INTEGER = 6
84    TIME_DURATION = 7
85    HIDDEN = 8
86    MULTIPLIER = 9
87    GREEN_PIPS = 10
88    RED_PIPS = 11
89    EXPLICIT_PERCENTAGE = 12
90    RAW_FLOAT = 13
91    LEVEL_AND_REWARD = 14

An enumeration.

AUTOMATIC = <ValueUIStyle.AUTOMATIC: 0>
FRACTION = <ValueUIStyle.FRACTION: 1>
CHECK_BOX = <ValueUIStyle.CHECK_BOX: 2>
PERCENTAGE = <ValueUIStyle.PERCENTAGE: 3>
DATETIME = <ValueUIStyle.DATETIME: 4>
FRACTION_FLOAT = <ValueUIStyle.FRACTION_FLOAT: 5>
INTEGER = <ValueUIStyle.INTEGER: 6>
TIME_DURATION = <ValueUIStyle.TIME_DURATION: 7>
HIDDEN = <ValueUIStyle.HIDDEN: 8>
MULTIPLIER = <ValueUIStyle.MULTIPLIER: 9>
GREEN_PIPS = <ValueUIStyle.GREEN_PIPS: 10>
RED_PIPS = <ValueUIStyle.RED_PIPS: 11>
EXPLICIT_PERCENTAGE = <ValueUIStyle.EXPLICIT_PERCENTAGE: 12>
RAW_FLOAT = <ValueUIStyle.RAW_FLOAT: 13>
LEVEL_AND_REWARD = <ValueUIStyle.LEVEL_AND_REWARD: 14>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class Vendor(builtins.int, aiobungie.Enum):
245@typing.final
246class Vendor(int, Enum):
247    """An Enum for all available vendors in Destiny 2."""
248
249    ZAVALA = 69482069
250    XUR = 2190858386
251    BANSHE = 672118013
252    SPIDER = 863940356
253    SHAXX = 3603221665
254    KADI = 529635856
255    """Postmaster exo."""
256    YUNA = 1796504621
257    """Asia servers only."""
258    EVERVERSE = 3361454721
259    AMANDA = 460529231
260    """Amanda holiday"""
261    CROW = 3611983588
262    HAWTHORNE = 3347378076
263    ADA1 = 350061650
264    DRIFTER = 248695599
265    IKORA = 1976548992
266    SAINT = 765357505
267    """Saint-14"""
268    ERIS_MORN = 1616085565
269    SHAW_HAWN = 1816541247
270    """COSMODROME Guy"""
271    VARIKS = 2531198101

An Enum for all available vendors in Destiny 2.

ZAVALA = <Vendor.ZAVALA: 69482069>
XUR = <Vendor.XUR: 2190858386>
BANSHE = <Vendor.BANSHE: 672118013>
SPIDER = <Vendor.SPIDER: 863940356>
SHAXX = <Vendor.SHAXX: 3603221665>
KADI = <Vendor.KADI: 529635856>

Postmaster exo.

YUNA = <Vendor.YUNA: 1796504621>

Asia servers only.

EVERVERSE = <Vendor.EVERVERSE: 3361454721>
AMANDA = <Vendor.AMANDA: 460529231>

Amanda holiday

CROW = <Vendor.CROW: 3611983588>
HAWTHORNE = <Vendor.HAWTHORNE: 3347378076>
ADA1 = <Vendor.ADA1: 350061650>
DRIFTER = <Vendor.DRIFTER: 248695599>
IKORA = <Vendor.IKORA: 1976548992>
SAINT = <Vendor.SAINT: 765357505>

Saint-14

ERIS_MORN = <Vendor.ERIS_MORN: 1616085565>
SHAW_HAWN = <Vendor.SHAW_HAWN: 1816541247>

COSMODROME Guy

VARIKS = <Vendor.VARIKS: 2531198101>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
@typing.final
class WeaponType(builtins.int, aiobungie.Enum):
532@typing.final
533class WeaponType(int, Enum):
534    """Enums for The three Destiny Weapon Types"""
535
536    NONE = 0
537    KINETIC = 1498876634
538    ENERGY = 2465295065
539    POWER = 953998645

Enums for The three Destiny Weapon Types

NONE = <WeaponType.NONE: 0>
KINETIC = <WeaponType.KINETIC: 1498876634>
ENERGY = <WeaponType.ENERGY: 2465295065>
POWER = <WeaponType.POWER: 953998645>
Inherited Members
Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
annotations = _Feature((3, 7, 0, 'beta', 1), (3, 11, 0, 'alpha', 0), 16777216)
def into_iter( iterable: collections.abc.Iterable[~Item]) -> aiobungie.FlatIterator[~Item]:
594def into_iter(
595    iterable: collections.Iterable[Item],
596) -> FlatIterator[Item]:
597    """Converts an iterable into an flat iterator.
598
599    Example
600    -------
601    >>> sequence = [1,2,3]
602    >>> async for item in aiobungie.into_iter(sequence).reversed():
603            print(item)
604    # 3
605    # 2
606    # 1
607
608    Parameters
609    ----------
610    iterable: `typing.Iterable[Item]`
611        The iterable to convert.
612
613    Raises
614    ------
615    `StopIteration`
616        If no elements are left in the iterator.
617    """
618    return FlatIterator(iterable)

Converts an iterable into an flat iterator.

Example
>>> sequence = [1,2,3]
>>> async for item in aiobungie.into_iter(sequence).reversed():
        print(item)
<h1 id="3">3</h1>

2

1

Parameters
  • iterable (typing.Iterable[Item]): The iterable to convert.
Raises
  • StopIteration: If no elements are left in the iterator.
async def raise_error( response: aiohttp.client_reqrep.ClientResponse) -> aiobungie.AiobungieError:
242async def raise_error(response: aiohttp.ClientResponse) -> AiobungieError:
243    """Generates and raise exceptions on error responses."""
244
245    # Not a JSON response, raise immediately.
246
247    # Also Bungie sometimes get funky and return HTML instead of JSON when making an authorized
248    # request with a dummy access token. I can't really do anything about this..
249    if response.content_type != "application/json":
250        return HTTPError(
251            f"Expected JSON content but got {response.content_type!s}, {response.real_url!s}",
252            http.HTTPStatus.UNSUPPORTED_MEDIA_TYPE,
253        )
254
255    body = await response.json()
256    message: str = body.get("Message", "UNDEFINED_MESSAGE")
257    error_status: str = body.get("ErrorStatus", "UNDEFINED_ERROR_STATUS")
258    message_data: dict[str, str] = body.get("MessageData", {})
259    throttle_seconds: int = body.get("ThrottleSeconds", 0)
260    error_code: int = body.get("ErrorCode", 0)
261
262    # Standard HTTP status.
263    if response.status == http.HTTPStatus.NOT_FOUND:
264        return NotFound(
265            message=message,
266            error_code=error_code,
267            throttle_seconds=throttle_seconds,
268            url=str(response.real_url),
269            body=body,
270            headers=response.headers,
271            error_status=error_status,
272            message_data=message_data,
273        )
274
275    elif response.status == http.HTTPStatus.FORBIDDEN:
276        return Forbidden(
277            message=message,
278            error_code=error_code,
279            throttle_seconds=throttle_seconds,
280            url=str(response.real_url),
281            body=body,
282            headers=response.headers,
283            error_status=error_status,
284            message_data=message_data,
285        )
286
287    elif response.status == http.HTTPStatus.UNAUTHORIZED:
288        return Unauthorized(
289            message=message,
290            error_code=error_code,
291            throttle_seconds=throttle_seconds,
292            url=str(response.real_url),
293            body=body,
294            headers=response.headers,
295            error_status=error_status,
296            message_data=message_data,
297        )
298
299    elif response.status == http.HTTPStatus.BAD_REQUEST:
300        # Membership needs to be alone.
301        if error_status == "InvalidParameters":
302            return MembershipTypeError(
303                message=message,
304                body=body,
305                headers=response.headers,
306                url=str(response.url),
307                membership_type=message_data["membershipType"],
308                required_membership=message_data["membershipInfo.membershipType"],
309                membership_id=int(message_data["membershipId"]),
310            )
311        return BadRequest(
312            message=message,
313            body=body,
314            headers=response.headers,
315            url=str(response.url),
316        )
317
318    status = http.HTTPStatus(response.status)
319
320    if 400 <= status < 500:
321        return ResponseError(
322            message=message,
323            error_code=error_code,
324            throttle_seconds=throttle_seconds,
325            url=str(response.real_url),
326            body=body,
327            headers=response.headers,
328            error_status=error_status,
329            message_data=message_data,
330            http_status=status,
331        )
332
333    # Need to self handle ~5xx errors
334    elif 500 <= status < 600:
335        # No API key or method requires OAuth2 most likely.
336        if error_status in {
337            "ApiKeyMissingFromRequest",
338            "WebAuthRequired",
339            "ApiInvalidOrExpiredKey",
340            "AuthenticationInvalid",
341            "AuthorizationCodeInvalid",
342        }:
343            return Unauthorized(
344                message=message,
345                error_code=error_code,
346                throttle_seconds=throttle_seconds,
347                url=str(response.real_url),
348                body=body,
349                headers=response.headers,
350                error_status=error_status,
351                message_data=message_data,
352            )
353
354        # Anything contains not found.
355        elif (
356            "NotFound" in error_status or error_status == "UserCannotFindRequestedUser"
357        ):
358            return NotFound(
359                message=message,
360                error_code=error_code,
361                throttle_seconds=throttle_seconds,
362                url=str(response.real_url),
363                body=body,
364                headers=response.headers,
365                error_status=error_status,
366                message_data=message_data,
367            )
368
369        # Other 5xx errors.
370        else:
371            return InternalServerError(
372                message=message,
373                error_code=error_code,
374                throttle_seconds=throttle_seconds,
375                url=str(response.real_url),
376                body=body,
377                headers=response.headers,
378                error_status=error_status,
379                message_data=message_data,
380                http_status=status,
381            )
382    # Something else.
383    else:
384        return HTTPException(
385            message=message,
386            error_code=error_code,
387            throttle_seconds=throttle_seconds,
388            url=str(response.real_url),
389            body=body,
390            headers=response.headers,
391            error_status=error_status,
392            message_data=message_data,
393            http_status=status,
394        )

Generates and raise exceptions on error responses.

def stringify_http_message(headers: 'collections.Mapping[str, str]') -> str:
397def stringify_http_message(headers: collections.Mapping[str, str]) -> str:
398    return (
399        "{ \n"
400        + "\n".join(  # noqa: W503
401            f"{f'   {key}'}: {value}"
402            if key not in ("Authorization", "X-API-KEY")
403            else f"   {key}: HIDDEN_TOKEN"
404            for key, value in headers.items()
405        )
406        + "\n}"  # noqa: W503
407    )